From efd31890b5ed496a5a00c08a262da240e66a4ddc Mon Sep 17 00:00:00 2001 From: Steve Langasek Date: Thu, 3 Jan 2019 12:44:11 -0800 Subject: New upstream version 0.76 --- .cvsignore | 9 - CHANGELOG | 1582 -------- Copyright | 41 - Linux-PAM/CHANGELOG | 1582 ++++++++ Linux-PAM/Copyright | 41 + Linux-PAM/Make.Rules.in | 110 + Linux-PAM/Makefile | 78 + Linux-PAM/README | 28 + Linux-PAM/_pam_aconf.h.in | 99 + Linux-PAM/bin/README | 30 + Linux-PAM/conf/Makefile | 34 + Linux-PAM/conf/install | 178 + Linux-PAM/conf/install_conf | 36 + Linux-PAM/conf/md5itall | 43 + Linux-PAM/conf/mkdirp | 50 + Linux-PAM/conf/pam.conf | 126 + Linux-PAM/conf/pam_conv1/Makefile | 46 + Linux-PAM/conf/pam_conv1/README | 10 + Linux-PAM/conf/pam_conv1/pam_conv.lex | 42 + Linux-PAM/conf/pam_conv1/pam_conv.y | 204 + Linux-PAM/configure | 3887 ++++++++++++++++++++ Linux-PAM/configure.in | 439 +++ Linux-PAM/defs/debian.defs | 40 + Linux-PAM/defs/hpux.defs | 36 + Linux-PAM/defs/linux.defs | 32 + Linux-PAM/defs/morgan.defs | 36 + Linux-PAM/defs/redhat.defs | 36 + Linux-PAM/defs/redhat4.defs | 35 + Linux-PAM/defs/solaris-2.1.5.defs | 45 + Linux-PAM/defs/solaris.defs | 48 + Linux-PAM/defs/sunos.defs | 37 + Linux-PAM/defs/suse.defs | 36 + Linux-PAM/doc/CREDITS | 49 + Linux-PAM/doc/Makefile | 167 + Linux-PAM/doc/NOTES | 16 + Linux-PAM/doc/figs/pam_orient.txt | 23 + Linux-PAM/doc/html/index.html | 21 + Linux-PAM/doc/man/pam.8 | 369 ++ Linux-PAM/doc/man/pam.conf.8 | 1 + Linux-PAM/doc/man/pam.d.8 | 1 + Linux-PAM/doc/man/pam_authenticate.3 | 91 + Linux-PAM/doc/man/pam_chauthtok.3 | 101 + Linux-PAM/doc/man/pam_close_session.3 | 1 + Linux-PAM/doc/man/pam_end.3 | 1 + Linux-PAM/doc/man/pam_fail_delay.3 | 130 + Linux-PAM/doc/man/pam_get_item.3 | 1 + Linux-PAM/doc/man/pam_open_session.3 | 99 + Linux-PAM/doc/man/pam_set_item.3 | 55 + Linux-PAM/doc/man/pam_setcred.3 | 79 + Linux-PAM/doc/man/pam_start.3 | 98 + Linux-PAM/doc/man/pam_strerror.3 | 51 + Linux-PAM/doc/man/template-man | 52 + Linux-PAM/doc/modules/README | 13 + Linux-PAM/doc/modules/module.sgml-template | 170 + Linux-PAM/doc/modules/pam_access.sgml | 117 + Linux-PAM/doc/modules/pam_chroot.sgml | 86 + Linux-PAM/doc/modules/pam_cracklib.sgml | 304 ++ Linux-PAM/doc/modules/pam_deny.sgml | 177 + Linux-PAM/doc/modules/pam_env.sgml | 141 + Linux-PAM/doc/modules/pam_filter.sgml | 150 + Linux-PAM/doc/modules/pam_ftp.sgml | 93 + Linux-PAM/doc/modules/pam_group.sgml | 108 + Linux-PAM/doc/modules/pam_issue.sgml | 120 + Linux-PAM/doc/modules/pam_krb4.sgml | 126 + Linux-PAM/doc/modules/pam_lastlog.sgml | 119 + Linux-PAM/doc/modules/pam_limits.sgml | 247 ++ Linux-PAM/doc/modules/pam_listfile.sgml | 138 + Linux-PAM/doc/modules/pam_mail.sgml | 142 + Linux-PAM/doc/modules/pam_mkhomedir.sgml | 83 + Linux-PAM/doc/modules/pam_motd.sgml | 77 + Linux-PAM/doc/modules/pam_nologin.sgml | 81 + Linux-PAM/doc/modules/pam_permit.sgml | 83 + Linux-PAM/doc/modules/pam_pwdb.sgml | 249 ++ Linux-PAM/doc/modules/pam_radius.sgml | 117 + Linux-PAM/doc/modules/pam_rhosts.sgml | 164 + Linux-PAM/doc/modules/pam_rootok.sgml | 85 + Linux-PAM/doc/modules/pam_securetty.sgml | 72 + Linux-PAM/doc/modules/pam_tally.sgml | 191 + Linux-PAM/doc/modules/pam_time.sgml | 166 + Linux-PAM/doc/modules/pam_unix.sgml | 288 ++ Linux-PAM/doc/modules/pam_userdb.sgml | 112 + Linux-PAM/doc/modules/pam_warn.sgml | 67 + Linux-PAM/doc/modules/pam_wheel.sgml | 125 + Linux-PAM/doc/pam_appl.sgml | 1782 +++++++++ Linux-PAM/doc/pam_modules.sgml | 1505 ++++++++ Linux-PAM/doc/pam_source.sgml | 1160 ++++++ Linux-PAM/doc/pdf/README | 3 + Linux-PAM/doc/ps/README | 3 + Linux-PAM/doc/specs/draft-morgan-pam.raw | 764 ++++ Linux-PAM/doc/specs/formatter/Makefile | 16 + Linux-PAM/doc/specs/formatter/parse.lex | 11 + Linux-PAM/doc/specs/formatter/parse.y | 293 ++ Linux-PAM/doc/specs/rfc86.0.txt | 1851 ++++++++++ Linux-PAM/doc/specs/std-agent-id.raw | 95 + Linux-PAM/doc/txts/README | 3 + Linux-PAM/dynamic/Makefile | 70 + Linux-PAM/dynamic/pam.c | 180 + Linux-PAM/dynamic/test.c | 27 + Linux-PAM/examples/Makefile | 54 + Linux-PAM/examples/blank.c | 158 + Linux-PAM/examples/check_user.c | 60 + Linux-PAM/examples/vpass.c | 47 + Linux-PAM/examples/wrap_xsh.sh | 5 + Linux-PAM/examples/xsh.c | 177 + Linux-PAM/libpam/Makefile | 151 + Linux-PAM/libpam/include/security/_pam_compat.h | 122 + Linux-PAM/libpam/include/security/_pam_macros.h | 187 + Linux-PAM/libpam/include/security/_pam_types.h | 324 ++ Linux-PAM/libpam/include/security/pam_appl.h | 92 + Linux-PAM/libpam/include/security/pam_malloc.h | 71 + Linux-PAM/libpam/include/security/pam_modules.h | 169 + Linux-PAM/libpam/pam_account.c | 23 + Linux-PAM/libpam/pam_auth.c | 68 + Linux-PAM/libpam/pam_data.c | 123 + Linux-PAM/libpam/pam_delay.c | 159 + Linux-PAM/libpam/pam_dispatch.c | 378 ++ Linux-PAM/libpam/pam_end.c | 77 + Linux-PAM/libpam/pam_env.c | 390 ++ Linux-PAM/libpam/pam_handlers.c | 897 +++++ Linux-PAM/libpam/pam_item.c | 333 ++ Linux-PAM/libpam/pam_log.c | 375 ++ Linux-PAM/libpam/pam_malloc.c | 418 +++ Linux-PAM/libpam/pam_map.c | 78 + Linux-PAM/libpam/pam_misc.c | 321 ++ Linux-PAM/libpam/pam_password.c | 57 + Linux-PAM/libpam/pam_private.h | 328 ++ Linux-PAM/libpam/pam_second.c | 50 + Linux-PAM/libpam/pam_session.c | 37 + Linux-PAM/libpam/pam_start.c | 112 + Linux-PAM/libpam/pam_static.c | 141 + Linux-PAM/libpam/pam_strerror.c | 93 + Linux-PAM/libpam/pam_tokens.h | 106 + Linux-PAM/libpam_misc/Makefile | 107 + Linux-PAM/libpam_misc/help_env.c | 105 + Linux-PAM/libpam_misc/include/security/pam_misc.h | 62 + Linux-PAM/libpam_misc/misc_conv.c | 380 ++ Linux-PAM/libpam_misc/xstrdup.c | 31 + Linux-PAM/libpamc/License | 42 + Linux-PAM/libpamc/Makefile | 107 + Linux-PAM/libpamc/include/security/pam_client.h | 197 + Linux-PAM/libpamc/libpamc.h | 63 + Linux-PAM/libpamc/pamc_client.c | 189 + Linux-PAM/libpamc/pamc_converse.c | 211 ++ Linux-PAM/libpamc/pamc_load.c | 477 +++ Linux-PAM/libpamc/test/agents/secret@here | 308 ++ Linux-PAM/libpamc/test/modules/Makefile | 9 + Linux-PAM/libpamc/test/modules/pam_secret.c | 670 ++++ Linux-PAM/libpamc/test/regress/Makefile | 7 + Linux-PAM/libpamc/test/regress/run_test.sh | 6 + Linux-PAM/libpamc/test/regress/test.libpamc.c | 342 ++ Linux-PAM/libpamc/test/regress/test.secret@here | 152 + Linux-PAM/modules/Makefile | 58 + Linux-PAM/modules/README | 55 + Linux-PAM/modules/Simple.Rules | 95 + Linux-PAM/modules/dont_makefile | 21 + Linux-PAM/modules/download-all | 30 + Linux-PAM/modules/install_conf | 49 + Linux-PAM/modules/pam_access/Makefile | 21 + Linux-PAM/modules/pam_access/README | 44 + Linux-PAM/modules/pam_access/access.conf | 58 + Linux-PAM/modules/pam_access/pam_access.c | 497 +++ Linux-PAM/modules/pam_cracklib/Makefile | 32 + Linux-PAM/modules/pam_cracklib/README | 37 + Linux-PAM/modules/pam_cracklib/pam_cracklib.c | 888 +++++ Linux-PAM/modules/pam_debug/Makefile | 15 + Linux-PAM/modules/pam_debug/README | 15 + Linux-PAM/modules/pam_debug/pam_debug.c | 175 + Linux-PAM/modules/pam_deny/Makefile | 15 + Linux-PAM/modules/pam_deny/README | 4 + Linux-PAM/modules/pam_deny/pam_deny.c | 81 + Linux-PAM/modules/pam_env/Makefile | 22 + Linux-PAM/modules/pam_env/README | 72 + Linux-PAM/modules/pam_env/pam_env.c | 842 +++++ Linux-PAM/modules/pam_env/pam_env.conf-example | 72 + Linux-PAM/modules/pam_filter/.upperLOWER | 1 + Linux-PAM/modules/pam_filter/Makefile | 126 + Linux-PAM/modules/pam_filter/README | 94 + Linux-PAM/modules/pam_filter/include/pam_filter.h | 32 + Linux-PAM/modules/pam_filter/pam_filter.c | 735 ++++ Linux-PAM/modules/pam_filter/upperLOWER/Makefile | 39 + .../modules/pam_filter/upperLOWER/upperLOWER.c | 164 + Linux-PAM/modules/pam_ftp/Makefile | 15 + Linux-PAM/modules/pam_ftp/README | 18 + Linux-PAM/modules/pam_ftp/pam_ftp.c | 297 ++ Linux-PAM/modules/pam_group/Makefile | 21 + Linux-PAM/modules/pam_group/group.conf | 60 + Linux-PAM/modules/pam_group/pam_group.c | 856 +++++ Linux-PAM/modules/pam_issue/Makefile | 15 + Linux-PAM/modules/pam_issue/pam_issue.c | 308 ++ Linux-PAM/modules/pam_lastlog/Makefile | 19 + Linux-PAM/modules/pam_lastlog/pam_lastlog.c | 462 +++ Linux-PAM/modules/pam_limits/Makefile | 31 + Linux-PAM/modules/pam_limits/README | 107 + Linux-PAM/modules/pam_limits/limits.skel | 45 + Linux-PAM/modules/pam_limits/pam_limits.c | 726 ++++ Linux-PAM/modules/pam_listfile/Makefile | 15 + Linux-PAM/modules/pam_listfile/README | 25 + Linux-PAM/modules/pam_listfile/pam_listfile.c | 439 +++ Linux-PAM/modules/pam_mail/Makefile | 15 + Linux-PAM/modules/pam_mail/README | 17 + Linux-PAM/modules/pam_mail/pam_mail.c | 499 +++ Linux-PAM/modules/pam_mkhomedir/Makefile | 15 + Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c | 377 ++ Linux-PAM/modules/pam_motd/Makefile | 15 + Linux-PAM/modules/pam_motd/pam_motd.c | 123 + Linux-PAM/modules/pam_nologin/Makefile | 15 + Linux-PAM/modules/pam_nologin/README | 23 + Linux-PAM/modules/pam_nologin/pam_nologin.c | 197 + Linux-PAM/modules/pam_permit/Makefile | 15 + Linux-PAM/modules/pam_permit/README | 4 + Linux-PAM/modules/pam_permit/pam_permit.c | 112 + Linux-PAM/modules/pam_pwdb/BUGS | 3 + Linux-PAM/modules/pam_pwdb/CHANGELOG | 10 + Linux-PAM/modules/pam_pwdb/Makefile | 124 + Linux-PAM/modules/pam_pwdb/README | 41 + Linux-PAM/modules/pam_pwdb/TODO | 34 + Linux-PAM/modules/pam_pwdb/bigcrypt.-c | 114 + Linux-PAM/modules/pam_pwdb/md5.c | 255 ++ Linux-PAM/modules/pam_pwdb/md5.h | 30 + Linux-PAM/modules/pam_pwdb/md5_crypt.c | 138 + Linux-PAM/modules/pam_pwdb/pam_pwdb.c | 248 ++ Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c | 272 ++ Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c | 131 + Linux-PAM/modules/pam_pwdb/pam_unix_md.-c | 73 + Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c | 373 ++ Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c | 260 ++ Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c | 98 + Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c | 221 ++ Linux-PAM/modules/pam_pwdb/support.-c | 943 +++++ Linux-PAM/modules/pam_radius/Makefile | 95 + Linux-PAM/modules/pam_radius/README | 58 + Linux-PAM/modules/pam_radius/pam_radius.c | 193 + Linux-PAM/modules/pam_radius/pam_radius.h | 40 + Linux-PAM/modules/pam_rhosts/Makefile | 15 + Linux-PAM/modules/pam_rhosts/README | 57 + Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c | 795 ++++ Linux-PAM/modules/pam_rootok/Makefile | 15 + Linux-PAM/modules/pam_rootok/README | 18 + Linux-PAM/modules/pam_rootok/pam_rootok.c | 110 + Linux-PAM/modules/pam_securetty/Makefile | 15 + Linux-PAM/modules/pam_securetty/README | 9 + Linux-PAM/modules/pam_securetty/pam_securetty.c | 191 + Linux-PAM/modules/pam_shells/Makefile | 15 + Linux-PAM/modules/pam_shells/README | 10 + Linux-PAM/modules/pam_shells/pam_shells.c | 133 + Linux-PAM/modules/pam_stress/Makefile | 15 + Linux-PAM/modules/pam_stress/README | 66 + Linux-PAM/modules/pam_stress/pam_stress.c | 565 +++ Linux-PAM/modules/pam_tally/Makefile | 103 + Linux-PAM/modules/pam_tally/README | 95 + Linux-PAM/modules/pam_tally/faillog.h | 55 + Linux-PAM/modules/pam_tally/pam_tally.c | 735 ++++ Linux-PAM/modules/pam_tally/pam_tally_app.c | 7 + Linux-PAM/modules/pam_time/Makefile | 21 + Linux-PAM/modules/pam_time/README | 30 + Linux-PAM/modules/pam_time/pam_time.c | 622 ++++ Linux-PAM/modules/pam_time/time.conf | 64 + Linux-PAM/modules/pam_unix/CHANGELOG | 55 + Linux-PAM/modules/pam_unix/Makefile | 167 + Linux-PAM/modules/pam_unix/README | 35 + Linux-PAM/modules/pam_unix/bigcrypt.c | 124 + Linux-PAM/modules/pam_unix/lckpwdf.-c | 117 + Linux-PAM/modules/pam_unix/md5.c | 256 ++ Linux-PAM/modules/pam_unix/md5.h | 31 + Linux-PAM/modules/pam_unix/md5_crypt.c | 154 + Linux-PAM/modules/pam_unix/pam_unix_acct.c | 204 + Linux-PAM/modules/pam_unix/pam_unix_auth.c | 228 ++ Linux-PAM/modules/pam_unix/pam_unix_passwd.c | 1030 ++++++ Linux-PAM/modules/pam_unix/pam_unix_sess.c | 141 + Linux-PAM/modules/pam_unix/support.c | 923 +++++ Linux-PAM/modules/pam_unix/support.h | 144 + Linux-PAM/modules/pam_unix/unix_chkpwd.c | 329 ++ Linux-PAM/modules/pam_unix/yppasswd.h | 51 + Linux-PAM/modules/pam_unix/yppasswd_xdr.c | 38 + Linux-PAM/modules/pam_userdb/Makefile | 37 + Linux-PAM/modules/pam_userdb/README | 30 + Linux-PAM/modules/pam_userdb/conv.c | 125 + Linux-PAM/modules/pam_userdb/create.pl | 23 + Linux-PAM/modules/pam_userdb/pam_userdb.c | 307 ++ Linux-PAM/modules/pam_userdb/pam_userdb.h | 61 + Linux-PAM/modules/pam_warn/Makefile | 15 + Linux-PAM/modules/pam_warn/README | 26 + Linux-PAM/modules/pam_warn/pam_warn.c | 127 + Linux-PAM/modules/pam_wheel/Makefile | 15 + Linux-PAM/modules/pam_wheel/README | 33 + Linux-PAM/modules/pam_wheel/pam_wheel.c | 276 ++ Linux-PAM/modules/pammodutil/Makefile | 53 + Linux-PAM/modules/pammodutil/README | 15 + .../pammodutil/include/security/_pam_modutil.h | 33 + Linux-PAM/modules/pammodutil/modutil_cleanup.c | 16 + Linux-PAM/modules/pammodutil/modutil_getpwnam.c | 80 + Linux-PAM/modules/pammodutil/modutil_getpwuid.c | 80 + Linux-PAM/modules/pammodutil/pammodutil.h | 22 + Linux-PAM/modules/register_static | 49 + Linux-PAM/pgp.keys.asc | 103 + Make.Rules.in | 110 - Makefile | 78 - README | 28 - _pam_aconf.h.in | 99 - bin/.cvsignore | 3 - bin/README | 30 - conf/.cvsignore | 2 - conf/Makefile | 34 - conf/install | 178 - conf/install_conf | 36 - conf/md5itall | 43 - conf/mkdirp | 50 - conf/pam.conf | 126 - conf/pam_conv1/.cvsignore | 3 - conf/pam_conv1/Makefile | 46 - conf/pam_conv1/README | 10 - conf/pam_conv1/pam_conv.lex | 42 - conf/pam_conv1/pam_conv.y | 204 - configure | 3887 -------------------- configure.in | 439 --- defs/debian.defs | 40 - defs/hpux.defs | 36 - defs/linux.defs | 32 - defs/morgan.defs | 36 - defs/redhat.defs | 36 - defs/redhat4.defs | 35 - defs/solaris-2.1.5.defs | 45 - defs/solaris.defs | 48 - defs/sunos.defs | 37 - defs/suse.defs | 36 - doc/.cvsignore | 2 - doc/CREDITS | 49 - doc/Makefile | 167 - doc/NOTES | 16 - doc/figs/pam_orient.txt | 23 - doc/html/.cvsignore | 1 - doc/html/index.html | 21 - doc/man/pam.8 | 369 -- doc/man/pam.conf.8 | 1 - doc/man/pam.d.8 | 1 - doc/man/pam_authenticate.3 | 91 - doc/man/pam_chauthtok.3 | 101 - doc/man/pam_close_session.3 | 1 - doc/man/pam_end.3 | 1 - doc/man/pam_fail_delay.3 | 130 - doc/man/pam_get_item.3 | 1 - doc/man/pam_open_session.3 | 99 - doc/man/pam_set_item.3 | 55 - doc/man/pam_setcred.3 | 79 - doc/man/pam_start.3 | 98 - doc/man/pam_strerror.3 | 51 - doc/man/template-man | 52 - doc/modules/README | 13 - doc/modules/module.sgml-template | 170 - doc/modules/pam_access.sgml | 117 - doc/modules/pam_chroot.sgml | 86 - doc/modules/pam_cracklib.sgml | 304 -- doc/modules/pam_deny.sgml | 177 - doc/modules/pam_env.sgml | 141 - doc/modules/pam_filter.sgml | 150 - doc/modules/pam_ftp.sgml | 93 - doc/modules/pam_group.sgml | 108 - doc/modules/pam_issue.sgml | 120 - doc/modules/pam_krb4.sgml | 126 - doc/modules/pam_lastlog.sgml | 119 - doc/modules/pam_limits.sgml | 247 -- doc/modules/pam_listfile.sgml | 138 - doc/modules/pam_mail.sgml | 142 - doc/modules/pam_mkhomedir.sgml | 83 - doc/modules/pam_motd.sgml | 77 - doc/modules/pam_nologin.sgml | 81 - doc/modules/pam_permit.sgml | 83 - doc/modules/pam_pwdb.sgml | 249 -- doc/modules/pam_radius.sgml | 117 - doc/modules/pam_rhosts.sgml | 164 - doc/modules/pam_rootok.sgml | 85 - doc/modules/pam_securetty.sgml | 72 - doc/modules/pam_tally.sgml | 191 - doc/modules/pam_time.sgml | 166 - doc/modules/pam_unix.sgml | 288 -- doc/modules/pam_userdb.sgml | 112 - doc/modules/pam_warn.sgml | 67 - doc/modules/pam_wheel.sgml | 125 - doc/pam_appl.sgml | 1782 --------- doc/pam_modules.sgml | 1505 -------- doc/pam_source.sgml | 1160 ------ doc/pdf/.cvsignore | 1 - doc/pdf/README | 3 - doc/ps/.cvsignore | 1 - doc/ps/README | 3 - doc/specs/.cvsignore | 1 - doc/specs/draft-morgan-pam.raw | 764 ---- doc/specs/formatter/.cvsignore | 3 - doc/specs/formatter/Makefile | 16 - doc/specs/formatter/parse.lex | 11 - doc/specs/formatter/parse.y | 293 -- doc/specs/rfc86.0.txt | 1851 ---------- doc/specs/std-agent-id.raw | 95 - doc/txts/.cvsignore | 1 - doc/txts/README | 3 - dynamic/Makefile | 70 - dynamic/pam.c | 180 - dynamic/test.c | 27 - examples/.cvsignore | 3 - examples/Makefile | 54 - examples/blank.c | 158 - examples/check_user.c | 60 - examples/vpass.c | 47 - examples/wrap_xsh.sh | 5 - examples/xsh.c | 177 - libpam/.cvsignore | 2 - libpam/Makefile | 151 - libpam/include/security/_pam_compat.h | 122 - libpam/include/security/_pam_macros.h | 187 - libpam/include/security/_pam_types.h | 324 -- libpam/include/security/pam_appl.h | 92 - libpam/include/security/pam_malloc.h | 71 - libpam/include/security/pam_modules.h | 169 - libpam/pam_account.c | 23 - libpam/pam_auth.c | 68 - libpam/pam_data.c | 123 - libpam/pam_delay.c | 159 - libpam/pam_dispatch.c | 378 -- libpam/pam_end.c | 77 - libpam/pam_env.c | 390 -- libpam/pam_handlers.c | 897 ----- libpam/pam_item.c | 333 -- libpam/pam_log.c | 375 -- libpam/pam_malloc.c | 418 --- libpam/pam_map.c | 78 - libpam/pam_misc.c | 321 -- libpam/pam_password.c | 57 - libpam/pam_private.h | 328 -- libpam/pam_second.c | 50 - libpam/pam_session.c | 37 - libpam/pam_start.c | 112 - libpam/pam_static.c | 141 - libpam/pam_strerror.c | 93 - libpam/pam_tokens.h | 106 - libpam_misc/.cvsignore | 9 - libpam_misc/Makefile | 107 - libpam_misc/help_env.c | 105 - libpam_misc/include/security/pam_misc.h | 62 - libpam_misc/misc_conv.c | 380 -- libpam_misc/xstrdup.c | 31 - libpamc/.cvsignore | 3 - libpamc/License | 42 - libpamc/Makefile | 107 - libpamc/include/security/pam_client.h | 197 - libpamc/libpamc.h | 63 - libpamc/pamc_client.c | 189 - libpamc/pamc_converse.c | 211 -- libpamc/pamc_load.c | 477 --- libpamc/test/agents/secret@here | 308 -- libpamc/test/modules/Makefile | 9 - libpamc/test/modules/pam_secret.c | 670 ---- libpamc/test/regress/Makefile | 7 - libpamc/test/regress/run_test.sh | 6 - libpamc/test/regress/test.libpamc.c | 342 -- libpamc/test/regress/test.secret@here | 152 - modules/Makefile | 58 - modules/README | 55 - modules/Simple.Rules | 95 - modules/dont_makefile | 21 - modules/download-all | 30 - modules/install_conf | 49 - modules/pam_access/.cvsignore | 1 - modules/pam_access/Makefile | 21 - modules/pam_access/README | 44 - modules/pam_access/access.conf | 58 - modules/pam_access/pam_access.c | 497 --- modules/pam_cracklib/.cvsignore | 1 - modules/pam_cracklib/Makefile | 32 - modules/pam_cracklib/README | 37 - modules/pam_cracklib/pam_cracklib.c | 888 ----- modules/pam_debug/.cvsignore | 2 - modules/pam_debug/Makefile | 15 - modules/pam_debug/README | 15 - modules/pam_debug/pam_debug.c | 175 - modules/pam_deny/.cvsignore | 1 - modules/pam_deny/Makefile | 15 - modules/pam_deny/README | 4 - modules/pam_deny/pam_deny.c | 81 - modules/pam_env/.cvsignore | 1 - modules/pam_env/Makefile | 22 - modules/pam_env/README | 72 - modules/pam_env/pam_env.c | 842 ----- modules/pam_env/pam_env.conf-example | 72 - modules/pam_filter/.cvsignore | 2 - modules/pam_filter/.upperLOWER | 1 - modules/pam_filter/Makefile | 126 - modules/pam_filter/README | 94 - modules/pam_filter/include/pam_filter.h | 32 - modules/pam_filter/pam_filter.c | 735 ---- modules/pam_filter/upperLOWER/.cvsignore | 1 - modules/pam_filter/upperLOWER/Makefile | 39 - modules/pam_filter/upperLOWER/upperLOWER.c | 164 - modules/pam_ftp/.cvsignore | 1 - modules/pam_ftp/Makefile | 15 - modules/pam_ftp/README | 18 - modules/pam_ftp/pam_ftp.c | 297 -- modules/pam_group/.cvsignore | 1 - modules/pam_group/Makefile | 21 - modules/pam_group/group.conf | 60 - modules/pam_group/pam_group.c | 856 ----- modules/pam_issue/.cvsignore | 1 - modules/pam_issue/Makefile | 15 - modules/pam_issue/pam_issue.c | 308 -- modules/pam_lastlog/.cvsignore | 1 - modules/pam_lastlog/Makefile | 19 - modules/pam_lastlog/pam_lastlog.c | 462 --- modules/pam_limits/.cvsignore | 1 - modules/pam_limits/Makefile | 31 - modules/pam_limits/README | 107 - modules/pam_limits/limits.skel | 45 - modules/pam_limits/pam_limits.c | 726 ---- modules/pam_listfile/.cvsignore | 1 - modules/pam_listfile/Makefile | 15 - modules/pam_listfile/README | 25 - modules/pam_listfile/pam_listfile.c | 439 --- modules/pam_mail/.cvsignore | 1 - modules/pam_mail/Makefile | 15 - modules/pam_mail/README | 17 - modules/pam_mail/pam_mail.c | 499 --- modules/pam_mkhomedir/.cvsignore | 1 - modules/pam_mkhomedir/Makefile | 15 - modules/pam_mkhomedir/pam_mkhomedir.c | 377 -- modules/pam_motd/.cvsignore | 1 - modules/pam_motd/Makefile | 15 - modules/pam_motd/pam_motd.c | 123 - modules/pam_nologin/.cvsignore | 1 - modules/pam_nologin/Makefile | 15 - modules/pam_nologin/README | 23 - modules/pam_nologin/pam_nologin.c | 197 - modules/pam_permit/.cvsignore | 1 - modules/pam_permit/Makefile | 15 - modules/pam_permit/README | 4 - modules/pam_permit/pam_permit.c | 112 - modules/pam_pwdb/.cvsignore | 2 - modules/pam_pwdb/BUGS | 3 - modules/pam_pwdb/CHANGELOG | 10 - modules/pam_pwdb/Makefile | 124 - modules/pam_pwdb/README | 41 - modules/pam_pwdb/TODO | 34 - modules/pam_pwdb/bigcrypt.-c | 114 - modules/pam_pwdb/md5.c | 255 -- modules/pam_pwdb/md5.h | 30 - modules/pam_pwdb/md5_crypt.c | 138 - modules/pam_pwdb/pam_pwdb.c | 248 -- modules/pam_pwdb/pam_unix_acct.-c | 272 -- modules/pam_pwdb/pam_unix_auth.-c | 131 - modules/pam_pwdb/pam_unix_md.-c | 73 - modules/pam_pwdb/pam_unix_passwd.-c | 373 -- modules/pam_pwdb/pam_unix_pwupd.-c | 260 -- modules/pam_pwdb/pam_unix_sess.-c | 98 - modules/pam_pwdb/pwdb_chkpwd.c | 221 -- modules/pam_pwdb/support.-c | 943 ----- modules/pam_radius/.cvsignore | 1 - modules/pam_radius/Makefile | 95 - modules/pam_radius/README | 58 - modules/pam_radius/pam_radius.c | 193 - modules/pam_radius/pam_radius.h | 40 - modules/pam_rhosts/.cvsignore | 1 - modules/pam_rhosts/Makefile | 15 - modules/pam_rhosts/README | 57 - modules/pam_rhosts/pam_rhosts_auth.c | 795 ---- modules/pam_rootok/.cvsignore | 1 - modules/pam_rootok/Makefile | 15 - modules/pam_rootok/README | 18 - modules/pam_rootok/pam_rootok.c | 110 - modules/pam_securetty/.cvsignore | 1 - modules/pam_securetty/Makefile | 15 - modules/pam_securetty/README | 9 - modules/pam_securetty/pam_securetty.c | 191 - modules/pam_shells/.cvsignore | 1 - modules/pam_shells/Makefile | 15 - modules/pam_shells/README | 10 - modules/pam_shells/pam_shells.c | 133 - modules/pam_stress/.cvsignore | 1 - modules/pam_stress/Makefile | 15 - modules/pam_stress/README | 66 - modules/pam_stress/pam_stress.c | 565 --- modules/pam_tally/.cvsignore | 2 - modules/pam_tally/Makefile | 103 - modules/pam_tally/README | 95 - modules/pam_tally/faillog.h | 55 - modules/pam_tally/pam_tally.c | 735 ---- modules/pam_tally/pam_tally_app.c | 7 - modules/pam_time/.cvsignore | 1 - modules/pam_time/Makefile | 21 - modules/pam_time/README | 30 - modules/pam_time/pam_time.c | 622 ---- modules/pam_time/time.conf | 64 - modules/pam_unix/.cvsignore | 4 - modules/pam_unix/CHANGELOG | 55 - modules/pam_unix/Makefile | 167 - modules/pam_unix/README | 35 - modules/pam_unix/bigcrypt.c | 124 - modules/pam_unix/lckpwdf.-c | 117 - modules/pam_unix/md5.c | 256 -- modules/pam_unix/md5.h | 31 - modules/pam_unix/md5_crypt.c | 154 - modules/pam_unix/pam_unix_acct.c | 204 - modules/pam_unix/pam_unix_auth.c | 228 -- modules/pam_unix/pam_unix_passwd.c | 1030 ------ modules/pam_unix/pam_unix_sess.c | 141 - modules/pam_unix/support.c | 923 ----- modules/pam_unix/support.h | 144 - modules/pam_unix/unix_chkpwd.c | 329 -- modules/pam_unix/yppasswd.h | 51 - modules/pam_unix/yppasswd_xdr.c | 38 - modules/pam_userdb/.cvsignore | 1 - modules/pam_userdb/Makefile | 37 - modules/pam_userdb/README | 30 - modules/pam_userdb/conv.c | 125 - modules/pam_userdb/create.pl | 23 - modules/pam_userdb/pam_userdb.c | 307 -- modules/pam_userdb/pam_userdb.h | 61 - modules/pam_warn/.cvsignore | 1 - modules/pam_warn/Makefile | 15 - modules/pam_warn/README | 26 - modules/pam_warn/pam_warn.c | 127 - modules/pam_wheel/.cvsignore | 1 - modules/pam_wheel/Makefile | 15 - modules/pam_wheel/README | 33 - modules/pam_wheel/pam_wheel.c | 276 -- modules/pammodutil/.cvsignore | 1 - modules/pammodutil/Makefile | 53 - modules/pammodutil/README | 15 - modules/pammodutil/include/security/_pam_modutil.h | 33 - modules/pammodutil/modutil_cleanup.c | 16 - modules/pammodutil/modutil_getpwnam.c | 80 - modules/pammodutil/modutil_getpwuid.c | 80 - modules/pammodutil/pammodutil.h | 22 - modules/register_static | 49 - pgp.keys.asc | 103 - 631 files changed, 52813 insertions(+), 52896 deletions(-) delete mode 100644 .cvsignore delete mode 100644 CHANGELOG delete mode 100644 Copyright create mode 100644 Linux-PAM/CHANGELOG create mode 100644 Linux-PAM/Copyright create mode 100644 Linux-PAM/Make.Rules.in create mode 100644 Linux-PAM/Makefile create mode 100644 Linux-PAM/README create mode 100644 Linux-PAM/_pam_aconf.h.in create mode 100644 Linux-PAM/bin/README create mode 100644 Linux-PAM/conf/Makefile create mode 100755 Linux-PAM/conf/install create mode 100755 Linux-PAM/conf/install_conf create mode 100755 Linux-PAM/conf/md5itall create mode 100755 Linux-PAM/conf/mkdirp create mode 100644 Linux-PAM/conf/pam.conf create mode 100644 Linux-PAM/conf/pam_conv1/Makefile create mode 100644 Linux-PAM/conf/pam_conv1/README create mode 100644 Linux-PAM/conf/pam_conv1/pam_conv.lex create mode 100644 Linux-PAM/conf/pam_conv1/pam_conv.y create mode 100755 Linux-PAM/configure create mode 100644 Linux-PAM/configure.in create mode 100644 Linux-PAM/defs/debian.defs create mode 100644 Linux-PAM/defs/hpux.defs create mode 100644 Linux-PAM/defs/linux.defs create mode 100644 Linux-PAM/defs/morgan.defs create mode 100644 Linux-PAM/defs/redhat.defs create mode 100644 Linux-PAM/defs/redhat4.defs create mode 100644 Linux-PAM/defs/solaris-2.1.5.defs create mode 100644 Linux-PAM/defs/solaris.defs create mode 100644 Linux-PAM/defs/sunos.defs create mode 100644 Linux-PAM/defs/suse.defs create mode 100644 Linux-PAM/doc/CREDITS create mode 100644 Linux-PAM/doc/Makefile create mode 100644 Linux-PAM/doc/NOTES create mode 100644 Linux-PAM/doc/figs/pam_orient.txt create mode 100644 Linux-PAM/doc/html/index.html create mode 100644 Linux-PAM/doc/man/pam.8 create mode 100644 Linux-PAM/doc/man/pam.conf.8 create mode 100644 Linux-PAM/doc/man/pam.d.8 create mode 100644 Linux-PAM/doc/man/pam_authenticate.3 create mode 100644 Linux-PAM/doc/man/pam_chauthtok.3 create mode 100644 Linux-PAM/doc/man/pam_close_session.3 create mode 100644 Linux-PAM/doc/man/pam_end.3 create mode 100644 Linux-PAM/doc/man/pam_fail_delay.3 create mode 100644 Linux-PAM/doc/man/pam_get_item.3 create mode 100644 Linux-PAM/doc/man/pam_open_session.3 create mode 100644 Linux-PAM/doc/man/pam_set_item.3 create mode 100644 Linux-PAM/doc/man/pam_setcred.3 create mode 100644 Linux-PAM/doc/man/pam_start.3 create mode 100644 Linux-PAM/doc/man/pam_strerror.3 create mode 100644 Linux-PAM/doc/man/template-man create mode 100644 Linux-PAM/doc/modules/README create mode 100644 Linux-PAM/doc/modules/module.sgml-template create mode 100644 Linux-PAM/doc/modules/pam_access.sgml create mode 100644 Linux-PAM/doc/modules/pam_chroot.sgml create mode 100644 Linux-PAM/doc/modules/pam_cracklib.sgml create mode 100644 Linux-PAM/doc/modules/pam_deny.sgml create mode 100644 Linux-PAM/doc/modules/pam_env.sgml create mode 100644 Linux-PAM/doc/modules/pam_filter.sgml create mode 100644 Linux-PAM/doc/modules/pam_ftp.sgml create mode 100644 Linux-PAM/doc/modules/pam_group.sgml create mode 100644 Linux-PAM/doc/modules/pam_issue.sgml create mode 100644 Linux-PAM/doc/modules/pam_krb4.sgml create mode 100644 Linux-PAM/doc/modules/pam_lastlog.sgml create mode 100644 Linux-PAM/doc/modules/pam_limits.sgml create mode 100644 Linux-PAM/doc/modules/pam_listfile.sgml create mode 100644 Linux-PAM/doc/modules/pam_mail.sgml create mode 100644 Linux-PAM/doc/modules/pam_mkhomedir.sgml create mode 100644 Linux-PAM/doc/modules/pam_motd.sgml create mode 100644 Linux-PAM/doc/modules/pam_nologin.sgml create mode 100644 Linux-PAM/doc/modules/pam_permit.sgml create mode 100644 Linux-PAM/doc/modules/pam_pwdb.sgml create mode 100644 Linux-PAM/doc/modules/pam_radius.sgml create mode 100644 Linux-PAM/doc/modules/pam_rhosts.sgml create mode 100644 Linux-PAM/doc/modules/pam_rootok.sgml create mode 100644 Linux-PAM/doc/modules/pam_securetty.sgml create mode 100644 Linux-PAM/doc/modules/pam_tally.sgml create mode 100644 Linux-PAM/doc/modules/pam_time.sgml create mode 100644 Linux-PAM/doc/modules/pam_unix.sgml create mode 100644 Linux-PAM/doc/modules/pam_userdb.sgml create mode 100644 Linux-PAM/doc/modules/pam_warn.sgml create mode 100644 Linux-PAM/doc/modules/pam_wheel.sgml create mode 100644 Linux-PAM/doc/pam_appl.sgml create mode 100644 Linux-PAM/doc/pam_modules.sgml create mode 100644 Linux-PAM/doc/pam_source.sgml create mode 100644 Linux-PAM/doc/pdf/README create mode 100644 Linux-PAM/doc/ps/README create mode 100644 Linux-PAM/doc/specs/draft-morgan-pam.raw create mode 100644 Linux-PAM/doc/specs/formatter/Makefile create mode 100644 Linux-PAM/doc/specs/formatter/parse.lex create mode 100644 Linux-PAM/doc/specs/formatter/parse.y create mode 100644 Linux-PAM/doc/specs/rfc86.0.txt create mode 100644 Linux-PAM/doc/specs/std-agent-id.raw create mode 100644 Linux-PAM/doc/txts/README create mode 100644 Linux-PAM/dynamic/Makefile create mode 100644 Linux-PAM/dynamic/pam.c create mode 100644 Linux-PAM/dynamic/test.c create mode 100644 Linux-PAM/examples/Makefile create mode 100644 Linux-PAM/examples/blank.c create mode 100644 Linux-PAM/examples/check_user.c create mode 100644 Linux-PAM/examples/vpass.c create mode 100755 Linux-PAM/examples/wrap_xsh.sh create mode 100644 Linux-PAM/examples/xsh.c create mode 100644 Linux-PAM/libpam/Makefile create mode 100644 Linux-PAM/libpam/include/security/_pam_compat.h create mode 100644 Linux-PAM/libpam/include/security/_pam_macros.h create mode 100644 Linux-PAM/libpam/include/security/_pam_types.h create mode 100644 Linux-PAM/libpam/include/security/pam_appl.h create mode 100644 Linux-PAM/libpam/include/security/pam_malloc.h create mode 100644 Linux-PAM/libpam/include/security/pam_modules.h create mode 100644 Linux-PAM/libpam/pam_account.c create mode 100644 Linux-PAM/libpam/pam_auth.c create mode 100644 Linux-PAM/libpam/pam_data.c create mode 100644 Linux-PAM/libpam/pam_delay.c create mode 100644 Linux-PAM/libpam/pam_dispatch.c create mode 100644 Linux-PAM/libpam/pam_end.c create mode 100644 Linux-PAM/libpam/pam_env.c create mode 100644 Linux-PAM/libpam/pam_handlers.c create mode 100644 Linux-PAM/libpam/pam_item.c create mode 100644 Linux-PAM/libpam/pam_log.c create mode 100644 Linux-PAM/libpam/pam_malloc.c create mode 100644 Linux-PAM/libpam/pam_map.c create mode 100644 Linux-PAM/libpam/pam_misc.c create mode 100644 Linux-PAM/libpam/pam_password.c create mode 100644 Linux-PAM/libpam/pam_private.h create mode 100644 Linux-PAM/libpam/pam_second.c create mode 100644 Linux-PAM/libpam/pam_session.c create mode 100644 Linux-PAM/libpam/pam_start.c create mode 100644 Linux-PAM/libpam/pam_static.c create mode 100644 Linux-PAM/libpam/pam_strerror.c create mode 100644 Linux-PAM/libpam/pam_tokens.h create mode 100644 Linux-PAM/libpam_misc/Makefile create mode 100644 Linux-PAM/libpam_misc/help_env.c create mode 100644 Linux-PAM/libpam_misc/include/security/pam_misc.h create mode 100644 Linux-PAM/libpam_misc/misc_conv.c create mode 100644 Linux-PAM/libpam_misc/xstrdup.c create mode 100644 Linux-PAM/libpamc/License create mode 100644 Linux-PAM/libpamc/Makefile create mode 100644 Linux-PAM/libpamc/include/security/pam_client.h create mode 100644 Linux-PAM/libpamc/libpamc.h create mode 100644 Linux-PAM/libpamc/pamc_client.c create mode 100644 Linux-PAM/libpamc/pamc_converse.c create mode 100644 Linux-PAM/libpamc/pamc_load.c create mode 100755 Linux-PAM/libpamc/test/agents/secret@here create mode 100644 Linux-PAM/libpamc/test/modules/Makefile create mode 100644 Linux-PAM/libpamc/test/modules/pam_secret.c create mode 100644 Linux-PAM/libpamc/test/regress/Makefile create mode 100755 Linux-PAM/libpamc/test/regress/run_test.sh create mode 100644 Linux-PAM/libpamc/test/regress/test.libpamc.c create mode 100755 Linux-PAM/libpamc/test/regress/test.secret@here create mode 100644 Linux-PAM/modules/Makefile create mode 100644 Linux-PAM/modules/README create mode 100644 Linux-PAM/modules/Simple.Rules create mode 100644 Linux-PAM/modules/dont_makefile create mode 100755 Linux-PAM/modules/download-all create mode 100755 Linux-PAM/modules/install_conf create mode 100644 Linux-PAM/modules/pam_access/Makefile create mode 100644 Linux-PAM/modules/pam_access/README create mode 100644 Linux-PAM/modules/pam_access/access.conf create mode 100644 Linux-PAM/modules/pam_access/pam_access.c create mode 100644 Linux-PAM/modules/pam_cracklib/Makefile create mode 100644 Linux-PAM/modules/pam_cracklib/README create mode 100644 Linux-PAM/modules/pam_cracklib/pam_cracklib.c create mode 100644 Linux-PAM/modules/pam_debug/Makefile create mode 100644 Linux-PAM/modules/pam_debug/README create mode 100644 Linux-PAM/modules/pam_debug/pam_debug.c create mode 100644 Linux-PAM/modules/pam_deny/Makefile create mode 100644 Linux-PAM/modules/pam_deny/README create mode 100644 Linux-PAM/modules/pam_deny/pam_deny.c create mode 100644 Linux-PAM/modules/pam_env/Makefile create mode 100644 Linux-PAM/modules/pam_env/README create mode 100644 Linux-PAM/modules/pam_env/pam_env.c create mode 100644 Linux-PAM/modules/pam_env/pam_env.conf-example create mode 100644 Linux-PAM/modules/pam_filter/.upperLOWER create mode 100644 Linux-PAM/modules/pam_filter/Makefile create mode 100644 Linux-PAM/modules/pam_filter/README create mode 100644 Linux-PAM/modules/pam_filter/include/pam_filter.h create mode 100644 Linux-PAM/modules/pam_filter/pam_filter.c create mode 100644 Linux-PAM/modules/pam_filter/upperLOWER/Makefile create mode 100644 Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c create mode 100644 Linux-PAM/modules/pam_ftp/Makefile create mode 100644 Linux-PAM/modules/pam_ftp/README create mode 100644 Linux-PAM/modules/pam_ftp/pam_ftp.c create mode 100644 Linux-PAM/modules/pam_group/Makefile create mode 100644 Linux-PAM/modules/pam_group/group.conf create mode 100644 Linux-PAM/modules/pam_group/pam_group.c create mode 100644 Linux-PAM/modules/pam_issue/Makefile create mode 100644 Linux-PAM/modules/pam_issue/pam_issue.c create mode 100644 Linux-PAM/modules/pam_lastlog/Makefile create mode 100644 Linux-PAM/modules/pam_lastlog/pam_lastlog.c create mode 100644 Linux-PAM/modules/pam_limits/Makefile create mode 100644 Linux-PAM/modules/pam_limits/README create mode 100644 Linux-PAM/modules/pam_limits/limits.skel create mode 100644 Linux-PAM/modules/pam_limits/pam_limits.c create mode 100644 Linux-PAM/modules/pam_listfile/Makefile create mode 100644 Linux-PAM/modules/pam_listfile/README create mode 100644 Linux-PAM/modules/pam_listfile/pam_listfile.c create mode 100644 Linux-PAM/modules/pam_mail/Makefile create mode 100644 Linux-PAM/modules/pam_mail/README create mode 100644 Linux-PAM/modules/pam_mail/pam_mail.c create mode 100644 Linux-PAM/modules/pam_mkhomedir/Makefile create mode 100644 Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c create mode 100644 Linux-PAM/modules/pam_motd/Makefile create mode 100644 Linux-PAM/modules/pam_motd/pam_motd.c create mode 100644 Linux-PAM/modules/pam_nologin/Makefile create mode 100644 Linux-PAM/modules/pam_nologin/README create mode 100644 Linux-PAM/modules/pam_nologin/pam_nologin.c create mode 100644 Linux-PAM/modules/pam_permit/Makefile create mode 100644 Linux-PAM/modules/pam_permit/README create mode 100644 Linux-PAM/modules/pam_permit/pam_permit.c create mode 100644 Linux-PAM/modules/pam_pwdb/BUGS create mode 100644 Linux-PAM/modules/pam_pwdb/CHANGELOG create mode 100644 Linux-PAM/modules/pam_pwdb/Makefile create mode 100644 Linux-PAM/modules/pam_pwdb/README create mode 100644 Linux-PAM/modules/pam_pwdb/TODO create mode 100644 Linux-PAM/modules/pam_pwdb/bigcrypt.-c create mode 100644 Linux-PAM/modules/pam_pwdb/md5.c create mode 100644 Linux-PAM/modules/pam_pwdb/md5.h create mode 100644 Linux-PAM/modules/pam_pwdb/md5_crypt.c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_pwdb.c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_md.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c create mode 100644 Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c create mode 100644 Linux-PAM/modules/pam_pwdb/support.-c create mode 100644 Linux-PAM/modules/pam_radius/Makefile create mode 100644 Linux-PAM/modules/pam_radius/README create mode 100644 Linux-PAM/modules/pam_radius/pam_radius.c create mode 100644 Linux-PAM/modules/pam_radius/pam_radius.h create mode 100644 Linux-PAM/modules/pam_rhosts/Makefile create mode 100644 Linux-PAM/modules/pam_rhosts/README create mode 100644 Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c create mode 100644 Linux-PAM/modules/pam_rootok/Makefile create mode 100644 Linux-PAM/modules/pam_rootok/README create mode 100644 Linux-PAM/modules/pam_rootok/pam_rootok.c create mode 100644 Linux-PAM/modules/pam_securetty/Makefile create mode 100644 Linux-PAM/modules/pam_securetty/README create mode 100644 Linux-PAM/modules/pam_securetty/pam_securetty.c create mode 100644 Linux-PAM/modules/pam_shells/Makefile create mode 100644 Linux-PAM/modules/pam_shells/README create mode 100644 Linux-PAM/modules/pam_shells/pam_shells.c create mode 100644 Linux-PAM/modules/pam_stress/Makefile create mode 100644 Linux-PAM/modules/pam_stress/README create mode 100644 Linux-PAM/modules/pam_stress/pam_stress.c create mode 100644 Linux-PAM/modules/pam_tally/Makefile create mode 100644 Linux-PAM/modules/pam_tally/README create mode 100644 Linux-PAM/modules/pam_tally/faillog.h create mode 100644 Linux-PAM/modules/pam_tally/pam_tally.c create mode 100644 Linux-PAM/modules/pam_tally/pam_tally_app.c create mode 100644 Linux-PAM/modules/pam_time/Makefile create mode 100644 Linux-PAM/modules/pam_time/README create mode 100644 Linux-PAM/modules/pam_time/pam_time.c create mode 100644 Linux-PAM/modules/pam_time/time.conf create mode 100644 Linux-PAM/modules/pam_unix/CHANGELOG create mode 100644 Linux-PAM/modules/pam_unix/Makefile create mode 100644 Linux-PAM/modules/pam_unix/README create mode 100644 Linux-PAM/modules/pam_unix/bigcrypt.c create mode 100644 Linux-PAM/modules/pam_unix/lckpwdf.-c create mode 100644 Linux-PAM/modules/pam_unix/md5.c create mode 100644 Linux-PAM/modules/pam_unix/md5.h create mode 100644 Linux-PAM/modules/pam_unix/md5_crypt.c create mode 100644 Linux-PAM/modules/pam_unix/pam_unix_acct.c create mode 100644 Linux-PAM/modules/pam_unix/pam_unix_auth.c create mode 100644 Linux-PAM/modules/pam_unix/pam_unix_passwd.c create mode 100644 Linux-PAM/modules/pam_unix/pam_unix_sess.c create mode 100644 Linux-PAM/modules/pam_unix/support.c create mode 100644 Linux-PAM/modules/pam_unix/support.h create mode 100644 Linux-PAM/modules/pam_unix/unix_chkpwd.c create mode 100644 Linux-PAM/modules/pam_unix/yppasswd.h create mode 100644 Linux-PAM/modules/pam_unix/yppasswd_xdr.c create mode 100644 Linux-PAM/modules/pam_userdb/Makefile create mode 100644 Linux-PAM/modules/pam_userdb/README create mode 100644 Linux-PAM/modules/pam_userdb/conv.c create mode 100644 Linux-PAM/modules/pam_userdb/create.pl create mode 100644 Linux-PAM/modules/pam_userdb/pam_userdb.c create mode 100644 Linux-PAM/modules/pam_userdb/pam_userdb.h create mode 100644 Linux-PAM/modules/pam_warn/Makefile create mode 100644 Linux-PAM/modules/pam_warn/README create mode 100644 Linux-PAM/modules/pam_warn/pam_warn.c create mode 100644 Linux-PAM/modules/pam_wheel/Makefile create mode 100644 Linux-PAM/modules/pam_wheel/README create mode 100644 Linux-PAM/modules/pam_wheel/pam_wheel.c create mode 100644 Linux-PAM/modules/pammodutil/Makefile create mode 100644 Linux-PAM/modules/pammodutil/README create mode 100644 Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h create mode 100644 Linux-PAM/modules/pammodutil/modutil_cleanup.c create mode 100644 Linux-PAM/modules/pammodutil/modutil_getpwnam.c create mode 100644 Linux-PAM/modules/pammodutil/modutil_getpwuid.c create mode 100644 Linux-PAM/modules/pammodutil/pammodutil.h create mode 100755 Linux-PAM/modules/register_static create mode 100644 Linux-PAM/pgp.keys.asc delete mode 100644 Make.Rules.in delete mode 100644 Makefile delete mode 100644 README delete mode 100644 _pam_aconf.h.in delete mode 100644 bin/.cvsignore delete mode 100644 bin/README delete mode 100644 conf/.cvsignore delete mode 100644 conf/Makefile delete mode 100755 conf/install delete mode 100755 conf/install_conf delete mode 100755 conf/md5itall delete mode 100755 conf/mkdirp delete mode 100644 conf/pam.conf delete mode 100644 conf/pam_conv1/.cvsignore delete mode 100644 conf/pam_conv1/Makefile delete mode 100644 conf/pam_conv1/README delete mode 100644 conf/pam_conv1/pam_conv.lex delete mode 100644 conf/pam_conv1/pam_conv.y delete mode 100755 configure delete mode 100644 configure.in delete mode 100644 defs/debian.defs delete mode 100644 defs/hpux.defs delete mode 100644 defs/linux.defs delete mode 100644 defs/morgan.defs delete mode 100644 defs/redhat.defs delete mode 100644 defs/redhat4.defs delete mode 100644 defs/solaris-2.1.5.defs delete mode 100644 defs/solaris.defs delete mode 100644 defs/sunos.defs delete mode 100644 defs/suse.defs delete mode 100644 doc/.cvsignore delete mode 100644 doc/CREDITS delete mode 100644 doc/Makefile delete mode 100644 doc/NOTES delete mode 100644 doc/figs/pam_orient.txt delete mode 100644 doc/html/.cvsignore delete mode 100644 doc/html/index.html delete mode 100644 doc/man/pam.8 delete mode 100644 doc/man/pam.conf.8 delete mode 100644 doc/man/pam.d.8 delete mode 100644 doc/man/pam_authenticate.3 delete mode 100644 doc/man/pam_chauthtok.3 delete mode 100644 doc/man/pam_close_session.3 delete mode 100644 doc/man/pam_end.3 delete mode 100644 doc/man/pam_fail_delay.3 delete mode 100644 doc/man/pam_get_item.3 delete mode 100644 doc/man/pam_open_session.3 delete mode 100644 doc/man/pam_set_item.3 delete mode 100644 doc/man/pam_setcred.3 delete mode 100644 doc/man/pam_start.3 delete mode 100644 doc/man/pam_strerror.3 delete mode 100644 doc/man/template-man delete mode 100644 doc/modules/README delete mode 100644 doc/modules/module.sgml-template delete mode 100644 doc/modules/pam_access.sgml delete mode 100644 doc/modules/pam_chroot.sgml delete mode 100644 doc/modules/pam_cracklib.sgml delete mode 100644 doc/modules/pam_deny.sgml delete mode 100644 doc/modules/pam_env.sgml delete mode 100644 doc/modules/pam_filter.sgml delete mode 100644 doc/modules/pam_ftp.sgml delete mode 100644 doc/modules/pam_group.sgml delete mode 100644 doc/modules/pam_issue.sgml delete mode 100644 doc/modules/pam_krb4.sgml delete mode 100644 doc/modules/pam_lastlog.sgml delete mode 100644 doc/modules/pam_limits.sgml delete mode 100644 doc/modules/pam_listfile.sgml delete mode 100644 doc/modules/pam_mail.sgml delete mode 100644 doc/modules/pam_mkhomedir.sgml delete mode 100644 doc/modules/pam_motd.sgml delete mode 100644 doc/modules/pam_nologin.sgml delete mode 100644 doc/modules/pam_permit.sgml delete mode 100644 doc/modules/pam_pwdb.sgml delete mode 100644 doc/modules/pam_radius.sgml delete mode 100644 doc/modules/pam_rhosts.sgml delete mode 100644 doc/modules/pam_rootok.sgml delete mode 100644 doc/modules/pam_securetty.sgml delete mode 100644 doc/modules/pam_tally.sgml delete mode 100644 doc/modules/pam_time.sgml delete mode 100644 doc/modules/pam_unix.sgml delete mode 100644 doc/modules/pam_userdb.sgml delete mode 100644 doc/modules/pam_warn.sgml delete mode 100644 doc/modules/pam_wheel.sgml delete mode 100644 doc/pam_appl.sgml delete mode 100644 doc/pam_modules.sgml delete mode 100644 doc/pam_source.sgml delete mode 100644 doc/pdf/.cvsignore delete mode 100644 doc/pdf/README delete mode 100644 doc/ps/.cvsignore delete mode 100644 doc/ps/README delete mode 100644 doc/specs/.cvsignore delete mode 100644 doc/specs/draft-morgan-pam.raw delete mode 100644 doc/specs/formatter/.cvsignore delete mode 100644 doc/specs/formatter/Makefile delete mode 100644 doc/specs/formatter/parse.lex delete mode 100644 doc/specs/formatter/parse.y delete mode 100644 doc/specs/rfc86.0.txt delete mode 100644 doc/specs/std-agent-id.raw delete mode 100644 doc/txts/.cvsignore delete mode 100644 doc/txts/README delete mode 100644 dynamic/Makefile delete mode 100644 dynamic/pam.c delete mode 100644 dynamic/test.c delete mode 100644 examples/.cvsignore delete mode 100644 examples/Makefile delete mode 100644 examples/blank.c delete mode 100644 examples/check_user.c delete mode 100644 examples/vpass.c delete mode 100755 examples/wrap_xsh.sh delete mode 100644 examples/xsh.c delete mode 100644 libpam/.cvsignore delete mode 100644 libpam/Makefile delete mode 100644 libpam/include/security/_pam_compat.h delete mode 100644 libpam/include/security/_pam_macros.h delete mode 100644 libpam/include/security/_pam_types.h delete mode 100644 libpam/include/security/pam_appl.h delete mode 100644 libpam/include/security/pam_malloc.h delete mode 100644 libpam/include/security/pam_modules.h delete mode 100644 libpam/pam_account.c delete mode 100644 libpam/pam_auth.c delete mode 100644 libpam/pam_data.c delete mode 100644 libpam/pam_delay.c delete mode 100644 libpam/pam_dispatch.c delete mode 100644 libpam/pam_end.c delete mode 100644 libpam/pam_env.c delete mode 100644 libpam/pam_handlers.c delete mode 100644 libpam/pam_item.c delete mode 100644 libpam/pam_log.c delete mode 100644 libpam/pam_malloc.c delete mode 100644 libpam/pam_map.c delete mode 100644 libpam/pam_misc.c delete mode 100644 libpam/pam_password.c delete mode 100644 libpam/pam_private.h delete mode 100644 libpam/pam_second.c delete mode 100644 libpam/pam_session.c delete mode 100644 libpam/pam_start.c delete mode 100644 libpam/pam_static.c delete mode 100644 libpam/pam_strerror.c delete mode 100644 libpam/pam_tokens.h delete mode 100644 libpam_misc/.cvsignore delete mode 100644 libpam_misc/Makefile delete mode 100644 libpam_misc/help_env.c delete mode 100644 libpam_misc/include/security/pam_misc.h delete mode 100644 libpam_misc/misc_conv.c delete mode 100644 libpam_misc/xstrdup.c delete mode 100644 libpamc/.cvsignore delete mode 100644 libpamc/License delete mode 100644 libpamc/Makefile delete mode 100644 libpamc/include/security/pam_client.h delete mode 100644 libpamc/libpamc.h delete mode 100644 libpamc/pamc_client.c delete mode 100644 libpamc/pamc_converse.c delete mode 100644 libpamc/pamc_load.c delete mode 100755 libpamc/test/agents/secret@here delete mode 100644 libpamc/test/modules/Makefile delete mode 100644 libpamc/test/modules/pam_secret.c delete mode 100644 libpamc/test/regress/Makefile delete mode 100755 libpamc/test/regress/run_test.sh delete mode 100644 libpamc/test/regress/test.libpamc.c delete mode 100755 libpamc/test/regress/test.secret@here delete mode 100644 modules/Makefile delete mode 100644 modules/README delete mode 100644 modules/Simple.Rules delete mode 100644 modules/dont_makefile delete mode 100755 modules/download-all delete mode 100755 modules/install_conf delete mode 100644 modules/pam_access/.cvsignore delete mode 100644 modules/pam_access/Makefile delete mode 100644 modules/pam_access/README delete mode 100644 modules/pam_access/access.conf delete mode 100644 modules/pam_access/pam_access.c delete mode 100644 modules/pam_cracklib/.cvsignore delete mode 100644 modules/pam_cracklib/Makefile delete mode 100644 modules/pam_cracklib/README delete mode 100644 modules/pam_cracklib/pam_cracklib.c delete mode 100644 modules/pam_debug/.cvsignore delete mode 100644 modules/pam_debug/Makefile delete mode 100644 modules/pam_debug/README delete mode 100644 modules/pam_debug/pam_debug.c delete mode 100644 modules/pam_deny/.cvsignore delete mode 100644 modules/pam_deny/Makefile delete mode 100644 modules/pam_deny/README delete mode 100644 modules/pam_deny/pam_deny.c delete mode 100644 modules/pam_env/.cvsignore delete mode 100644 modules/pam_env/Makefile delete mode 100644 modules/pam_env/README delete mode 100644 modules/pam_env/pam_env.c delete mode 100644 modules/pam_env/pam_env.conf-example delete mode 100644 modules/pam_filter/.cvsignore delete mode 100644 modules/pam_filter/.upperLOWER delete mode 100644 modules/pam_filter/Makefile delete mode 100644 modules/pam_filter/README delete mode 100644 modules/pam_filter/include/pam_filter.h delete mode 100644 modules/pam_filter/pam_filter.c delete mode 100644 modules/pam_filter/upperLOWER/.cvsignore delete mode 100644 modules/pam_filter/upperLOWER/Makefile delete mode 100644 modules/pam_filter/upperLOWER/upperLOWER.c delete mode 100644 modules/pam_ftp/.cvsignore delete mode 100644 modules/pam_ftp/Makefile delete mode 100644 modules/pam_ftp/README delete mode 100644 modules/pam_ftp/pam_ftp.c delete mode 100644 modules/pam_group/.cvsignore delete mode 100644 modules/pam_group/Makefile delete mode 100644 modules/pam_group/group.conf delete mode 100644 modules/pam_group/pam_group.c delete mode 100644 modules/pam_issue/.cvsignore delete mode 100644 modules/pam_issue/Makefile delete mode 100644 modules/pam_issue/pam_issue.c delete mode 100644 modules/pam_lastlog/.cvsignore delete mode 100644 modules/pam_lastlog/Makefile delete mode 100644 modules/pam_lastlog/pam_lastlog.c delete mode 100644 modules/pam_limits/.cvsignore delete mode 100644 modules/pam_limits/Makefile delete mode 100644 modules/pam_limits/README delete mode 100644 modules/pam_limits/limits.skel delete mode 100644 modules/pam_limits/pam_limits.c delete mode 100644 modules/pam_listfile/.cvsignore delete mode 100644 modules/pam_listfile/Makefile delete mode 100644 modules/pam_listfile/README delete mode 100644 modules/pam_listfile/pam_listfile.c delete mode 100644 modules/pam_mail/.cvsignore delete mode 100644 modules/pam_mail/Makefile delete mode 100644 modules/pam_mail/README delete mode 100644 modules/pam_mail/pam_mail.c delete mode 100644 modules/pam_mkhomedir/.cvsignore delete mode 100644 modules/pam_mkhomedir/Makefile delete mode 100644 modules/pam_mkhomedir/pam_mkhomedir.c delete mode 100644 modules/pam_motd/.cvsignore delete mode 100644 modules/pam_motd/Makefile delete mode 100644 modules/pam_motd/pam_motd.c delete mode 100644 modules/pam_nologin/.cvsignore delete mode 100644 modules/pam_nologin/Makefile delete mode 100644 modules/pam_nologin/README delete mode 100644 modules/pam_nologin/pam_nologin.c delete mode 100644 modules/pam_permit/.cvsignore delete mode 100644 modules/pam_permit/Makefile delete mode 100644 modules/pam_permit/README delete mode 100644 modules/pam_permit/pam_permit.c delete mode 100644 modules/pam_pwdb/.cvsignore delete mode 100644 modules/pam_pwdb/BUGS delete mode 100644 modules/pam_pwdb/CHANGELOG delete mode 100644 modules/pam_pwdb/Makefile delete mode 100644 modules/pam_pwdb/README delete mode 100644 modules/pam_pwdb/TODO delete mode 100644 modules/pam_pwdb/bigcrypt.-c delete mode 100644 modules/pam_pwdb/md5.c delete mode 100644 modules/pam_pwdb/md5.h delete mode 100644 modules/pam_pwdb/md5_crypt.c delete mode 100644 modules/pam_pwdb/pam_pwdb.c delete mode 100644 modules/pam_pwdb/pam_unix_acct.-c delete mode 100644 modules/pam_pwdb/pam_unix_auth.-c delete mode 100644 modules/pam_pwdb/pam_unix_md.-c delete mode 100644 modules/pam_pwdb/pam_unix_passwd.-c delete mode 100644 modules/pam_pwdb/pam_unix_pwupd.-c delete mode 100644 modules/pam_pwdb/pam_unix_sess.-c delete mode 100644 modules/pam_pwdb/pwdb_chkpwd.c delete mode 100644 modules/pam_pwdb/support.-c delete mode 100644 modules/pam_radius/.cvsignore delete mode 100644 modules/pam_radius/Makefile delete mode 100644 modules/pam_radius/README delete mode 100644 modules/pam_radius/pam_radius.c delete mode 100644 modules/pam_radius/pam_radius.h delete mode 100644 modules/pam_rhosts/.cvsignore delete mode 100644 modules/pam_rhosts/Makefile delete mode 100644 modules/pam_rhosts/README delete mode 100644 modules/pam_rhosts/pam_rhosts_auth.c delete mode 100644 modules/pam_rootok/.cvsignore delete mode 100644 modules/pam_rootok/Makefile delete mode 100644 modules/pam_rootok/README delete mode 100644 modules/pam_rootok/pam_rootok.c delete mode 100644 modules/pam_securetty/.cvsignore delete mode 100644 modules/pam_securetty/Makefile delete mode 100644 modules/pam_securetty/README delete mode 100644 modules/pam_securetty/pam_securetty.c delete mode 100644 modules/pam_shells/.cvsignore delete mode 100644 modules/pam_shells/Makefile delete mode 100644 modules/pam_shells/README delete mode 100644 modules/pam_shells/pam_shells.c delete mode 100644 modules/pam_stress/.cvsignore delete mode 100644 modules/pam_stress/Makefile delete mode 100644 modules/pam_stress/README delete mode 100644 modules/pam_stress/pam_stress.c delete mode 100644 modules/pam_tally/.cvsignore delete mode 100644 modules/pam_tally/Makefile delete mode 100644 modules/pam_tally/README delete mode 100644 modules/pam_tally/faillog.h delete mode 100644 modules/pam_tally/pam_tally.c delete mode 100644 modules/pam_tally/pam_tally_app.c delete mode 100644 modules/pam_time/.cvsignore delete mode 100644 modules/pam_time/Makefile delete mode 100644 modules/pam_time/README delete mode 100644 modules/pam_time/pam_time.c delete mode 100644 modules/pam_time/time.conf delete mode 100644 modules/pam_unix/.cvsignore delete mode 100644 modules/pam_unix/CHANGELOG delete mode 100644 modules/pam_unix/Makefile delete mode 100644 modules/pam_unix/README delete mode 100644 modules/pam_unix/bigcrypt.c delete mode 100644 modules/pam_unix/lckpwdf.-c delete mode 100644 modules/pam_unix/md5.c delete mode 100644 modules/pam_unix/md5.h delete mode 100644 modules/pam_unix/md5_crypt.c delete mode 100644 modules/pam_unix/pam_unix_acct.c delete mode 100644 modules/pam_unix/pam_unix_auth.c delete mode 100644 modules/pam_unix/pam_unix_passwd.c delete mode 100644 modules/pam_unix/pam_unix_sess.c delete mode 100644 modules/pam_unix/support.c delete mode 100644 modules/pam_unix/support.h delete mode 100644 modules/pam_unix/unix_chkpwd.c delete mode 100644 modules/pam_unix/yppasswd.h delete mode 100644 modules/pam_unix/yppasswd_xdr.c delete mode 100644 modules/pam_userdb/.cvsignore delete mode 100644 modules/pam_userdb/Makefile delete mode 100644 modules/pam_userdb/README delete mode 100644 modules/pam_userdb/conv.c delete mode 100644 modules/pam_userdb/create.pl delete mode 100644 modules/pam_userdb/pam_userdb.c delete mode 100644 modules/pam_userdb/pam_userdb.h delete mode 100644 modules/pam_warn/.cvsignore delete mode 100644 modules/pam_warn/Makefile delete mode 100644 modules/pam_warn/README delete mode 100644 modules/pam_warn/pam_warn.c delete mode 100644 modules/pam_wheel/.cvsignore delete mode 100644 modules/pam_wheel/Makefile delete mode 100644 modules/pam_wheel/README delete mode 100644 modules/pam_wheel/pam_wheel.c delete mode 100644 modules/pammodutil/.cvsignore delete mode 100644 modules/pammodutil/Makefile delete mode 100644 modules/pammodutil/README delete mode 100644 modules/pammodutil/include/security/_pam_modutil.h delete mode 100644 modules/pammodutil/modutil_cleanup.c delete mode 100644 modules/pammodutil/modutil_getpwnam.c delete mode 100644 modules/pammodutil/modutil_getpwuid.c delete mode 100644 modules/pammodutil/pammodutil.h delete mode 100755 modules/register_static delete mode 100644 pgp.keys.asc diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index 4cae323b..00000000 --- a/.cvsignore +++ /dev/null @@ -1,9 +0,0 @@ -default.defs -.freezemake -.filelist -include -config.status -config.log -config.cache -_pam_aconf.h -Make.Rules diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 03d6045a..00000000 --- a/CHANGELOG +++ /dev/null @@ -1,1582 +0,0 @@ - -$Id$ - ------------------------------ - -TODO: - - - sanitize use of md5 throughout distribution.. Make a static - library for helping to develop modules that contains it and other - stuff. Also add sha-1 and ripemd-160 digest algorithms. - - once above is done. remove hacks from the secret@here module etc.. - - remove prototype for gethostname in pam_access.c (Derrick) - - document PAM_INCOMPLETE changes - - verify that the PAM_INCOMPLETE interface is sensible. Can we - catch errors? should we permit item changing etc., between - pam_authenticate re-invocations? - - verify that the PAM_INCOMPLETE interface works (auth seems ok..) - - add PAM_INCOMPLETE support to modules (partially added to pam_pwdb) - - work on RFC. - - do we still need to remove openlog/closelog from modules..? - - auth and acct support in pam_cracklib, "yes, I know the password - you just typed was valid, I just don't think it was very strong..." - - add in the pam_cap and pam_netid modules - -==================================================================== -Note, as of release 0.73, all checkins should be accompanied with a -Bug ID. The bug IDs relate to sourceforge IDs.. (Of course, nothing is -ever that simple. It turns out that at some point in Sourceforge's -history all of the bug ids got bumped by 100000, so pretty much if you -see a bug ID below that begins with a '1' and your attempted query -fails, try adding 100000 to the number and trying again. I believe -this only affects bugs before release 0.76.) - -You can query the related bug description with the following URL: - - http://sourceforge.net/tracker/index.php?func=detail&aid=XXXXXX&group_id=6663&atid=106663 - -Where you should replace XXXXXX with a bug-id. - -For general documentation completion work, I'm doing it all with -respect to specific tasks. Open tasks are listed here: - - http://sourceforge.net/pm/task.php?group_id=6663&group_project_id=2741&func=browse&set=open - -If you have found a bug in Linux-PAM (including a documentation bug, -or a new feature request and/or patch), please consider filing such a -bug report - outstanding bugs are listed here: - - http://sourceforge.net/tracker/?atid=106663&group_id=6663&func=browse - -(to file another bug see the 'submit bug' button on that page). - -==================================================================== - -0.76: please submit patches for this section with actual code/doc - patches! - -* pam_unix: fix for legacy crypt() support when the password entered - was long. (Bug 521314 - agmorgan). -* pam_access no longer include gethostname() prototype complained from - David Lee (Bug 415423 - agmorgan). -* make pam_nologin more secure by default, added two new module - arguments etc. - acting on suggestion from Nico (Bug 419307 - - agmorgan) -* link in libpam to libpam_misc - since the latter uses functions in - the former it makes some sort of sense to do this (although, in the - static library case, I remain to be convinced). (Bug 565470 - - agmorgan). -* absorbed some of the proposed darwin (OS X) changes from Luke Howard - (of PADL software) - hopefully will get the rest (see Rob Braun's - 534205) by 0.77 (Bug 491466 - agmorgan). -* README fix for pam_unix from Nalin (Bug 476971 - agmorgan). -* add support for building pdf files from the documentation - request - from 'lolive' (Bug 471377 - agmorgan). -* documented the equivalent '[..]' expressions for "required" - etc. Request from Ross Patterson (Bug 529078 - agmorgan). -* '[...]' parsing: document it and also fix it to support '\]' escape - sequence. Feature request from Russell Kliese (Bug 517064 - - agmorgan). -* pam_rootok: compilation warning noted by Tony den Haan wrt no - prototype for strcmp() (Bug 557322 - agmorgan). -* documentation: (a few of mine in passing) and app documentation - suggestions regarding PAM environment variables and module - documentation changes regarding the conversation function from Jenn - Vesperman (Bug 527821, 527965 - agmorgan) -* documentation: pam_time.sgml typo fixed, pam_motd exists now, - correct Red Hat comment about config files (Bugs 554274, 554261, - 554182 - agmorgan) -* pam_limits: added '%' domain for maxlogins limiting, now '*' and @group - have the old meaning (every) and '%' the new one (all) - (Bug 533664 - baggins) -* pam_limits: put not so interesting log messages under debug arg - (Bug 533668 - baggins) -* pam_access: added the 'fieldsep=' argument (Bug 547051 - agmorgan), - made a PAM_RHOST of "" equivalent to NULL (Bug 547521 - agmorgan). -* pam_limits: keep well know behaviour of maxlogins default ('*') limit - (Bug 533664 - baggins) -* pam_unix: more from Nalin log password changes (Bug 517743 - agmorgan) -* pam_limits: make it use the priority value specified in config - (bug 530428 - baggins) -* pam_unix: removed broken code in password update code. Report from - Len Lattanzi (Bug 507379 - agmorgan) -* pam_mkhomedir: recurse directories. Patch from Nalin (Bug 476981 - - agmorgan) -* pam_limits can handle negative priority limits now (which can apply - to the superuser too) - based on patch from Nalin. Also cleanup the - error handling that was very sloppy before. Also, courtesy of Berend - De Schouwe get the math right on login counting (Bug 476990, 476987, - 493294 - agmorgan) -* documentation: random typo fixes from Nalin and more stuff from me - (Bug 476949, Tasks 43507, 17426 - agmorgan) -* A Tru64 fix (given other stuff has already resolved this, it - actually just a comment actually) from 'Eddie'. (Bug 418450 - - agmorgan) -* pam_handlers: BSD fix from Dag-Erling Smørgrav and Anton Berezin - (Bug 486063 - agmorgan) -* added the dynamic/* directory to the distribution. If you go in - there after building the rest of the tree, you'll make a pam.so - object that can be used by something like a java runtime with - dlopen. Its not very well tested - caveat emptor. (Bug 232194 - - agmorgan) -* somehow pam_unix has started forcing the user prompt to be "login: ". - This is entirely inapropriate as it overrides PAM_USER_PROMPT. (Bug - 486361 - agmorgan). -* added a static module helper library object includes a few changes - to examples/xsh.c for testing purposes (added a simple shell wrapper - for running xsh with the sandbox libraries), and also modified the - pam_rhosts_auth module to use this new library. (Bug 490938, 409852 - - agmorgan). -* pam_unix: fix 'likeauth' to kill off the memory leak once and for all. - (Bug 483959 - vorlon) -* pam_unix: restore handling of 'likeauth' argument to a known working - state; prettify AUTH_RETURN macro; remove redundant argv checks in - pam_sm_setcred() (Bugs 483959, 113596 - vorlon) -* pam_cracklib: another try at implementing similar() from Harald - Welte and Nalin (Bugs 436053, 476957 - agmorgan) -* pam_access: default access.conf file contained a type (console - instead of LOCAL) fix from Nalin (Bug 476934 - agmorgan) -* pam_unix: fixed bizarre memory leak pointed out by Fernando Trias - (Bug 483959 - agmorgan) -* misc string comparison length checking changes from Nalin. Modules - touched, pam_cracklib, pam_listfile, pam_unix, pam_wheel (Bug 476947 - - agmorgan) -* pam_userdb: require that all of typed password matches that in - database report and fix from Vladimir Pastukhov. (Bug 484252 - agmorgan) -* pam_malloc: revived malloc debugging code, now tied to - --enable-memory-debug and added strdup() support (Bug 485454 - agmorgan) -* pam_tally: Nalin's fix for lastlog corruption (Bug 476985 - agmorgan) -* pam_rhosts: Nalin adds support for '+hostname', and zdd fix - compilation warning. (Bug 476986 - agmorgan) -* pam_motd: Nalin fixed compiler warning. (Bug 476938 - agmorgan) -* pam_pwdb: Solar Designer pointed out that there was a problem with - the compatibility support for md5 password hashing. (Bug 460717, - 476961 - agmorgan) -* pam_issue: Nalin found segfaulting problems if the PAM_USER_PROMPT - is unset, found some similar problems with assumptions about - realloc. (Bug 476983 - agmorgan) -* pam_env: 'weichangyang of hotmail' pointed out a wild string with no - valid '\0' was leading to problems with sshd and suggested fix (Bug - 473034 - agmorgan) -* MANDIR cleanup. It defaults to /usr/share/man, but can be overridden - using the --enable-mandir ./configure option, similarly for DOCDIR - from Nalin (Bug 476940 - agmorgan) -* pam_filter cleanup (including moving the filter directory) Nalin - and Harald Welte (Bugs 436057, 476970 - agmorgan) -* db3 is now recognized as a libdb candidate (Bug 435764 - agmorgan) -* more changes (extracted from redhat version) courtesy of - Harald Welte (Bugs pam_limits=436061, pam_lastlog=436060, - pam_mkhomedir/pam_env=435991 - agmorgan) -* fix for legacy behavior of pam_setcred and pam_close_session in - the case that pam_authenticate and pam_open_session hadn't been - called - bug report from Seongwan Park. (Bug 468724 - agmorgan) -* some BSD updates and fixes from Mark Murray - including a slightly - more robust conversation function and some minimization of gcc - warnings. (Bugs 449203,463984 - agmorgan) -* verified that the setcred stack didn't suffer from the bug I was - nervous about, add a new module pam_debug to help me test this. - fixed a libpam/pam_dispatch.c instrumentation line that I tripped - over when testing. Also restructured pam_warn to help here (Bug - 424315 - agmorgan). -* pam_unix/support.c: sample use of reentrant NSS function. Not yet active, - because modules do not include _pam_aconf_h! (Bug 440107 - vorlon) -* doc/Makefile changes - use $(mandir) [courtesy Harald Welte] (Bug - 435760) and add some rules to make/delete the draft rfc I've been - working on (Task 17426 - agmorgan) -* pam_modules.sgml: sourceforge has changed its CVS viewing software - (Bug 460491 - agmorgan) -* pam_unix_passwd: got rid of an annoying warning (Bug 461089 - agmorgan) -* configure.in, _pam_aconf.h.in: set the stage for fully reentrant PAM - modules, with some infrastructure to detect getxxbyxx_r() functions - (Bug 440107 - vorlon) -* pam_unix: removed superfluous use of static variables in md5 and bigcrypt - routines, bringing us a step closer to thread-safeness. Eliminated - some variable indirection along the way. (Bug 440107 - vorlon) -* pam_tally: remove #include of stdlib.h, which isn't needed by anything - found in this module. Can be readded if we find a real need for it at - a later date. (Bug 436432 - vorlon) -* pam_tally: added an #include (was it really needed?) and made the - pam_tally app install (with more pretty printing and a corrected - Makefile dependency) motivated by a (red hat diff) courtesy of Harald - Welte (Bug 436432 - agmorgan) -* configure.in changes to help support non-Linux environments courtesy - of Scott T. Emery (Bug 422563 - agmorgan) -* made a pam_cracklib enhancement to interpret -ve limits in a - sensible fashion contributed by Werner Puschitz (Bug 413162 - - agmorgan) -* another fix for the latest number of rlimits available to pam_limits - (Bug 424060 - agmorgan) -* removed stale link from pam_pwdb documentation (Bug 433460 - agmorgan) -* pam_appl.sgml change - more discussion of choosing a service name - (Bug 417512 - agmorgan) -* more specific linking requirements for -lndbm for pam_userdb - from - David Lee (Bug 417339 - agmorgan) -* a large number of small changes to make AIX support better (Bug - 416229 - agmorgan) -* $(MAKE) instead of 'make' - from Scott T. Emery (Bug 422144 - - agmorgan) -* c++ header fixes for pam_misc.h and pam_client.h - from Alexandre - Sagala (Bug 420270 - agmorgan) -* pam_access fixes - looks out for trailing '.' - from Carlo Marcelo - Arenas Belon (Bug 419631 - agmorgan) -* don't zero out password strings during pam_unix's password changing - function (Bug 419803 - vorlon) -* propagate some definitions to the _pam_aconf.h file - from David Lee - (Bug 415419 - agmorgan) -* solaris GCC OS_CFLAGS change from David Lee (Bug 415412 - agmorgan) -* added a comment to this CHANGELOG to explain why most of the bugids - used below appear not to be known to sourceforge [try adding 100000 - to the bugid number.] (Bug 414943 - agmorgan) -* bumped version numbers and also added support for SONAME defines - that appear not to have survived the great autoconf experiment (Bug - 414669 - agmorgan). - -0.75: Sat Apr 7 23:10:50 PDT 2001 - - ** WARNING ** - -This release contains backwardly incompatible changes to -libpam. Prior versions were buggy - see bugfix for Bug 129775. - - ** WARNING ** - -* made 0.75 release (Bug 414665 - agmorgan) -* pam_pwdb has been removed from the suggested pam.conf template. I've - replaced it with pam_unix. (Bug 227565 - agmorgan) -* pam_limits - Richard M. Yumul reported that " -" didn't - work, first fix suggested by Werner Puschitz (Bug 404953 - agmorgan) -* Nicolay Pelov suggested a simple fix for freebsd support (Bug 407282 - - agmorgan) -* Michel D'HOOGE submitted documentation fixes (Bug 408961 - agmorgan) -* fix for module linking directions (Bug 133545 - agmorgan) -* fix for glibc-2.2.2 compilation of pam_issue (Bug 133542 - agmorgan) -* fix pam_userdb to make and link both .o files it needs - converse() - wasn't being linked! (Bug 132880 - agmorgan) -* added some sys-admin documentation for the pam_tally module (Bug - 126210 - agmorgan). -* added a link to module examples from the module writers doc (Bug - 131192 - agmorgan). -* fixed a small security hole (more of a user confusion issue) with - the unix and pwdb password helper binaries. The beef is described in - the bug report, but no uid change was possible so no-one should - think they need to issue a security bulletin over this one! (Bug - 112540 - agmorgan) -* pam_lastlog needs to be linked with -lutil, also removed ambiguity - from sysadmin guide regarding this module being a 'session' module - (Bug 131549 - agmorgan). -* pam_cracklib needs to be linked with -lcrypt (old password checking) - (Bug 131601 - agmorgan). -* fixes for static library builds and also the examples when linked - with the debugging build of the libraries. (Bug 131783 - agmorgan) -* fixed URL for original RFC to a cached kernel.org file. (Bug 131503 - - agmorgan) -* quoted the $CRACKLIB_DICTPATH test in configure.in (Bug 130130 - - agmorgan). -* improved handling of the setcred/close_session and update chauthtok - stack. *Warning* This is a backwardly incompatable change, but 'more - sane' than before. (Bug 129775 - agmorgan) -* bumped the version number, and added some code to assist in making - documentation releases (Bug 129644 - agmorgan). - -0.74: Sun Jan 21 22:36:08 PST 2001 - -* made 0.74 release (Bug 129642 - agmorgan) -* libpam - cleaned up a few non-static functions to be static and added - support for libpam to enforce things like pam_[gs]et_data() and - AUTHTOK rules for using the API. Also documented pam_[gs]et_item() - a little better including return codes (Bugs 129027, 128576 - - agmorgan). -* pam_access - fixed the non-default config file option (Bug 127561 - - agmorgan) -* pam.8 manual page clarified with respect to the default location for - finding modules, also added some text describing the [...] control - syntax. (Bug 127625 - agmorgan) -* md5.h ia64 fixes for pam_unix and pam_pwdb (Bug 127700 - agmorgan) -* removed requirement for c++ from the configure{.in,} files (Bug - 128298 - agmorgan) -* removed subdirectories from man page redirections (124396 - baggins) -* per David Lee, fixed non-POSIX shell command in modules/pam_filter/Makefile - (Bug 126440 - vorlon) -* modify format of pam_unix log messages to include service name - (Bug 126423 - vorlon) -* prevent pam_unix from logging unknown usernames (Bug 126431 - vorlon) -* changed format of pam_unix 'authentication failure' log messages to make - them clearer and more consistent (Bug 126036 - vorlon) -* improved portability of pam_unix by eliminating Linux-specific utmp - defines in PAM_getlogin() (Bug 125704 - vorlon) -* removed static variables from pam_tally (Bug 117434 - agmorgan) -* added copyright message to pam_access module from original logdaemon - sources (Bug 125022 - agmorgan) -* configure.in - removed the GCC -Wtraditional flag (Bug 124923 - agmorgan) -* pam_mail - use PAM_PATH_MAILDIR as the location of mail spool - (Bug 124397 - baggins) -* _pam_aconf.h.in, configure.in - added PAM_PATH_MAILDIR set via - --with-mailspool=dir option (default is _PAM_MAILDIR if defined - in paths.h otherwise /var/spool/mail (Bug 124397 - baggins) -* removed unnecessary CVS Log tags from all over the source - (Bug 124391 - baggins) -* pam_tally - check for PAM_TTY if PAM_RHOST is not set when writing - to faillog (Bug 124394 - baggins) -* use O_NOFOLLOW if available when opening debug log (Bug 124385 - baggins) -* pam_cracklib - removed comments about pam_unix not working with - pam_cracklib, added information about use_authtok parameter - (Bug 124388 - baggins) -* pam_userdb - fixed wrong definition of struct pam_module (was pam_wheel) - (Bug 124386 - baggins) -* fixed example/Makefile include path (Bug 124187, 127563(?) - agmorgan) -* pam_userdb compiles on RH5x. Also removed circular dependency on - configure.in. Also bumped revision number to 0.74. (Bug 124136 - - agmorgan) - -0.73: Sat Dec 2 00:04:04 PST 2000 - -* updated documentaion revisions and added 'make release' support - to the top level Makefile (Bug 124132 - agmorgan). -* documented Qmail support in pam_mail (Bug 109219 - baggins) -* add change_uid option to pam_limits, and set real uid only if - this option is present (Bug 124062 - baggins) -* pam_limits - set real uid to the user for who we set limits. - (Bug 123972 - baggins) -* removed static variables from pam_limits (thread safe now). (Bug - 117450 - agmorgan). -* removed static variable from pam_wheel (module should be thread safe - now). (Bug 112906 - agmorgan) -* added support for '/' symbols in pam_time and pam_group config files - (support for modern terminal devices). Fixed infinite loop problem - with '\\[^\n]' in these files. (Bug 116076 - agmorgan) -* avoid potential SIGPIPE when writing to helper binaries with (Bug - 123399 - agmorgan) -* replaced bogus logic in the pam_cracklib module for determining if - the replacement is too similar to the old password (Bug 115055 - - agmorgan) -* added accessconf= feature to pam_access - request from - Aldrin Martoq and Meelis Roos (Bugs 111927,117240 - agmorgan) -* fix for pam_limit module not dealing with all limits Adam J. Richter - (Bug 119554 - agmorgan) -* comment fix describing fail_delay callback in _pam_types.h (Bug - 112646 - agmorgan) -* "likeauth" fix for pam_unix and pam_pwdb which (Bug 113596 - agmorgan) -* fix for pam_unix (support.c) to avoid segfault with NULL password - (Bug 113238 - vorlon) -* fix to pam_unix_passwd: try repeatedly to get a lock on the password - file, instead of failing immediately (Bug 108845 - fix vorlon) -* fix to pam_shells: logged information was not formatted correctly - (extra comma) (Bug 111491 - fix vorlon) -* fix for C++ application support (Bug 111645 - fix agmorgan) -* fix for typo in pam_client.h (Bug 111648 - fix agmorgan) -* removal of -lpam from pam_mkhomedir Makefile (Bug 116380 - fix agmorgan) -* autoconf support [Task ID 15788, Bug ID 108297 - agmorgan with help!] - - bugfix for libpamc.h include file [Bug ID 117476 - agmorgan] - - bugfix for pam_filter.h inclusion [Bug ID 117474 - agmorgan] - -0.72: Mon Dec 13 22:41:11 PST 1999 - -* patches from Debian (Ben Collins): pam_ftp supports event driven - conversations now; pwdb_chkpwd cleanup; pam_warn static compile fix; - user_db compiler warnings removed; debian defs file; pam_mail can - now be used as a session module -* ndbm compilation option for user_db module (fix explained by Richard Khoo) -* pam_cracklib bug fix -* packaging fixes & build from scratch stuff (Konst Bulatnikov & Frodo - Looijaard) -* -ldl appended to the libpam.so compilation make rule. (Charles Seeger) -* Red Hat security patch for pam_pwdb forwarded by Debian! (Ben - Collins. Fix provided by Andrey as it caught the problem earlier in the - code.) -* heuristic to prevent leaking filedescriptors to an agent. [This needs - to be better supported perhaps by an additional libpamc API function?] -* pam_userdb segfault fix from (Ben Collins) -* PAM draft spec extras added at request of 'sen_ml' - -0.71: Sun Nov 7 20:21:19 PST 1999 - -* added -lc to linker pass for pam_nologin module (glibc is weird). -* various header changes to lower the number of warnings on glibc - systems (Dan Yefimov) -* merged a bunch of Debian fixes/patches/documentation (Ben Collins) - things touched: libpam (minor); doc/modules/pam_unix.sgml; pam_env - (plus docs); pam_mkhomedir (new module for new home directories on - the fly...); pam_motd (new module); pam_limits (adjust to match - docs); pam_issue (new module + doc) [Some of these were also - submitted by Thorsten Kukuk] -* small hack to lower the number of warnings that pam_client.h was - generating. -* debian and SuSE apparently can use the pam_ftp module, so - removed the obsolete comment about this from the docs. (Thorsten - Kukuk) - -0.70: Fri Oct 8 22:05:30 PDT 1999 - -* bug fix for parsing of value=action tokens in libpam/pam_misc.c was - segfaulting (Jan Rekorajski and independently Matthew Melvin) -* numerous fixes from Thorsten Kukuk (icluding much needed fixes for - bitrot in modules and some documentation) that got included in SuSE 6.2. -* reentrancy issues in pam_unix and pam_cracklib resolved (Jan Rekorajski) -* added hosts_equiv_rootok module option to pam_rhosts module (Tim Berger) -* added comment about 'expose_account' module argument to admin and - module writers' docs (request from Michael K Johnson). -* myriad of bug fixes for libpamc - library now built by default and - works with the biomouse fingerprint scanner agent/module - (distributed separately). - -0.69: Sun Aug 1 20:25:37 PDT 1999 - -* c++ header #ifdef'ing for pam_appl.h (Tuomo Pyhala) -* added pam_userdb module (Cristian Gafton) -* minor documentation changes -* added in revised pam_client library (libpamc). Not installed by - default yet, since the example agent/module combo is not very secure. -* glibc fixes (Thorsten Kukuk, Adam J. Richter) - -0.68: Sun Jul 4 23:04:13 PDT 1999 - -* completely new pam_unix module from Jan Rekorajski and Stephen Langasek -* Jan Rekorajski pam_mail - support for Maildir format mailboxes -* Jan Rekorajski pam_cracklib - support for old password comparison -* Jan Rekorajski bug fix for pam_pwdb setcred reusing auth retval -* Andrey's pam_tally patch (lstat -> fstat) -* Robert Milkowski's additional pam_tally patches to **change format of - /var/log/faillog** to one from shadow-utils, add new option "per_user" - for pam_tally module, failure time logging, support for fail_line - field, and support for fail_locktime field with new option - no_lock_time. -* pam_tally: clean up the tally application too. -* Marcin Korzonek added process priority settings to pam_limits (bonus - points for adding to documentation!) -* Andrey's pam_pwdb patch (cleanup + md5 endian fubar fix) -* more binary prompt preparations (make misc conv more compatible with spec) -* modified callback hook for fail delay to be more useful with event - driven applications (changed function prototype - suspect no one - will notice). Documented this in app developer guide. -* documentation for pam_access from Tim Berger -* syntax fixes for the documentation - a long time since I've built it :*( - added some more names to the CREDITS file. - -0.67: Sat Jun 19 14:01:24 PDT 1999 - -* [dropped libpam_client - libpamc will be in the next release and - conforms to the developing spec in doc/specs/draft-morgan-pam.raw. - Sorry if you are keeping a PAM tree in CVS. CVS is a pain for - directories, but this directory was actually not referenced by - anything so the disruption should be light.] -* updates to pam_tally from Tim -* multiple updates from Stephen Langasek to pam_unix -* pam_filter had some trouble compiling (bug report from Sridhar) -* pam_wheel now attempts to identify the wheel group for the local - system instead of blindly assuming it is gid=0. In the case that - there is no "wheel" group, we default to assuming gid=0 is what was - meant - former behavior. (courtesy of Sridhar) -* NIS+ changes to pam_unix module from Dmitry O Panov -* hopefully, a fix for redefinition of LOG_AUTHPRIV (bug report Luke - Kenneth Casson Leighton) -* fix for minor typo in pam_wheel documentation (Jacek Kopecky) -* slightly more explanation of the [x=y] pam.conf syntax in the sys - admin guide. - -0.66: Mon Dec 28 20:22:23 PST 1998 - -* Started using cvs to keep track of changes to Linux-PAM. This will - likely break some of the automated building stuff (RPMs etc..). -* security bug fix to pam_unix and pam_tally from Andrey. -* modules make file is now more automatic. It should be possible to - unpack an external module in the modules directory and have it automatically - added to the build process. Also added a modules/download-all script - that will make such downloading easier. I'm happy to receive patches to - this file, informing the distribution of places from which to enrich itself. -* removed pam_system_log stuff. Thought about it long and hard: a - bad idea. If libc cannot guarantee a thread safe syslog, it needs - to be fixed and compatibility with other PAM libraries was - unnecessarily strained. -* SAG documentation changes: Seth Chaiklin -* rhosts: problems with NIS lookup failures with the root-uid check. - As a work-around, I've partially eliminated the need for the lookup - by supplying two new arguments: no_uid_check, superuser=. - As a general rule this is more pluggable, since this module might be - used as an authentication scheme for a network service that does not - need root privilege... -* authenticate retval -> setcred for pam_pwdb (likeauth arg). -* pam_pwdb event driven support -* non openlog pam_listfile logging -* BUGFIX: close filedescriptor in pam_group and pam_time (Emmanuel Galanos) -* Chris Adams' mailhash change for pam_mail module -* fixed malloc failure check in pam_handlers.c (follow up to comment - by Brad M. Garcia). -* update to _pam_compat.h (Brad M. Garcia) -* support static modules in libpam again (Brad M. Garcia) -* libpam/pam_misc.c for egcs to grok the code (Brad M. Garcia) -* added a solaris-2.5.1 defs file (revived by Derrick J Brashear) -* pam_listfile logs failed attempts -* added a comment (Michael K Johnson pointed it out) about sgml2latex - having a new syntax. I'll make it the change real when I upgrade... -* a little more text to the RFC, spelling fix from William J Buffam. -* minor changes to pam_securetty to accommodate event driven support. - -0.65: Sun Apr 5 22:29:09 PDT 1998 - -* added event driven programming extensions to libpam - - added PAM_INCOMPLETE handling to libpam/pam_dispatch.c - - added PAM_CONV_AGAIN which is a new conversation response that - should be mapped to PAM_INCOMPLETE by the module. - - ensured that the pam_get_user() function can resume - - changes to pam_strerror to accommodate above return codes - - clean up _pam_former_state at pam_end() - - ensured that former state is correctly initialized - - added resumption tests to pam_authenticate(), pam_chauthtok() - - added PAM_FAIL_DELAY item for pausing on failure - -* improved _pam_macros.h so that macros can be used as single commands - (Andrey) - -* reimplemented logging to avoid bad interactions with libc. Added - new functions, pam_[,v]system_log() to libpam's API. A programmer - can check for this function's availablility by checking if - HAVE_PAM_SYSTEM_LOG is #defined. - -* removed the reduce conflict from pam_conv1 creation -- I can sleep - again now. :^] - -* made building of static and dynamic libpam separate. This is - towards making it possible to build both under Solaris (for Derrick) - -* made USE_CRACKLIB a condition in unix module (Luke Kenneth Casson Leighton) - -* automated (quiet) config installation (Andrey) - -0.64: Thu Feb 19 23:30:24 PST 1998 Andrew Morgan - -* miscellaneous patches for building under Solaris (Derrick J Brashear) - -* removed STATIC support from a number of module Makefiles. Notably, - these modules are those that use libpwdb and caused difficulties - satisfying the build process. (Please submit patches to fix this...;) - -* reomved the union for binary packet conversations from - (_pam_types.h). This is now completely implemented in libpam_client. - -* Andrey's patch for working environment variable handling in - sh_secret module. - -* made the libpam_misc conversation function a bit more flexible with - respect to binary conversations. - -* added top level define (DEBUG_REL) for compiling in the form of - a debugging release. I use this on a Red Hat 4.2 system with little - chance of crashing the system as a whole. (Andrey has another - implementation of this -- with a spec file to match..) - -0.63: Wed Jan 28 22:55:30 PST 1998 Andrew Morgan - -* added libpam_client "convention" library. This makes explicit the - use of PAM_BINARY_PROMPT. It is a first cut, so don't take it too - seriously yet. Comments/suggestions for improvements are very - welcome. Note, this library does not compile by default. It will - be enabled when it is judged stable. The library comes with two - module/agent pairs and can be used with ssh using a patch available - from my pre-release directory [where you got this file.] - -* backward compatibility patch for libpam/pam_handlers.c (PAM_IGNORE - was working with neither "requistie" nor "required") and a DEBUG'ing - compile time bug with pam_dispatch.c (Savochkin Andrey Vladimirovich) - -* minor Makefile change from (Savochkin Andrey Vladimirovich) - -* added pam_afsauth, pam_afspass, pam_restrict, and pam_syslog hooks - (Derrick J Brashear) - -* pam_access use of uname(2) problematic (security problem - highlighted by Olaf Kirch). - -* pam_listfile went a bit crazy reading group membersips (problem - highlighted by Olaf Kirch and patched independently by Cristian - Gafton and Savochkin Andrey Vladimirovich) - -* compatibility hooks for solaris and hpux (Derrick J Brashear) - -* 64 bit Linux/alpha bug fixed in pam_rhosts (Andrew D. Isaacson) - -0.62: Wed Jan 14 14:10:55 PST 1998 Andrew Morgan - -* Derrick J Brashear's patches: adds the HP stuff missed in the first - patch; adds SunOS support; adds support for the Solaris native ld - instead of requiring gnu ld. - -* last line of .rhosts file need not contain a newline. (Bug reported by - Thompson Freeman.) - -0.61: Thu Jan 8 22:57:44 PST 1998 Andrew Morgan - -* complete rewrite of the "control flag" logic. Formerly, we were - limited to four flags: requisite, required, sufficient, optional. - We can now use these keywords _and_ a great deal more besides. - The extra logic was inspired by Vipin Samar, a preliminary patch was - written by Andy Berkheimer, but I "had some ideas of my own" and - that's what I've actually included. The basic idea is to allow the - admin to custom build a control flag with a series of token=value - pairs inside square brackets. Eg., '[default=die success=ok]' which - is pretty close to a synonym for 'requisite'. I'll try to document it - better in the sys-admin guide but I'm pretty sure it is a change for - the better.... If what is in the sys-admin guide is not good enough - for you, just take a look at the source for libpam ;^) - -0.59: Thu Jan 8 22:27:22 PST 1998 Andrew Morgan - -* better handling of empty lines in .rhosts file. (Formerly, we asked - the nameserver about them!) Fix from Hugh Daschbach. - -* _broke_some_binary_compatibility_ with previous versions to become - compliant with X/Open's XSSO spec. Specifically, this has been - by changing the prototype for pam_strerror(). - -* altered the convention for the conversation mechanism to agree - with that of Sun. (number of responses 'now=' number of messages - with help from Cristian for finding a bug.. Cristian also found a - nasty speradic segfault bug -- Thanks!) - -* added NIS+ support to pam_unix_* - -* fixed a "regular file checking" problem with the ~/.rhosts sanity - check. Added "privategroup" option to permit group write permission - on the ~/.rhosts file in the case that the group owner has the same - name as the authenticating user. :*) "promiscuous" and "suppress" - were not usable! - -* added glibc compatibility to pam_rhosts_auth (protected __USE_MISC - with #ifndef since my libc already defines it!). - -* Security fix from Savochkin Andrey Vladimirovich with suggested - modification from Olaf Seibert. - -* preC contains mostly code clean-ups and a number of changes to - _pam_macros. - -0.58: whenever - -* pam_getenvlist() has a more robust definition (XSSO) than was previously - thought. It would seem that we no longer need pam_misc_copy_env() - which was there to provide the robustness that pam_getenvlist() - lacked before... - - Accordingly, I have REMOVED the prototype from libpam_misc. (The - function, however, will remain in the library as a wrapper for - legacy apps, but will likely be removed from libpam_misc-1.0.) PLEASE - FIX YOUR APPS *BEFORE* WE GET THERE! - -* Alexy Nogin reported garbage output from pam_env in the case of - a non-existent environment variable. - -* 'fixed' pwdb compilation for pam_wheel. Not very cleanly - done.. Mmmm. Should really clean up the entire source tree... - -* added prototypes for mapping functions - - <**WARNING**> - - various constants have had there names changed. Numerical values have - been retained but be aware some source old modules/applications will - need to be fixed before recompilation. - - - -* appended documentation to README for pam_rhosts module (Nicolai - Langfeldt). - -* verified X/Open compatibility of header files - note, where we differ - it is at the level of compilation warnings and the use of 'const char *' - instead of 'char *'. Previously, Sun(X/open) have revised their spec - to be more 'const'-ervative in the light of comments from Linux-PAM - development. - -* Ooops! PAM_AUTHTOKEN_REQD should have been PAM_NEW_AUTHTOK_REQD. - - changed: pam_pwdb(pam_unix_acct) (also bug fix for - _shadow_acct_mgmt_exp() return value), pam_stress, - libpam/pam_dispatch, blank, xsh. - -* New: PAM_AUTHTOK_EXPIRED - password has expired. - -* Ooops! PAM_CRED_ESTABLISH (etc.) should have been PAM_ESTABLISH_CRED - etc... (changed - this may break some people's modules - PLEASE TAKE - NOTE!) - changed: pam_group, pam_mail, blank, xsh; module and appl - docs, pam_setcred manual page. - -* renamed internal _pam_handle structure to be pam_handle as per XSSO. - -* added PAM_RADIO_TYPE (for multiple choice input method). Also - added PAM_BINARY_{MSG,PROMPT} (for interaction out of sight of user - - this could be used for RSA type authentication but is currently - just there for experimental purposes). The _BINARY_ types are now - usable with hooks in the libpam_misc conversation function. Still - have to add PAM_RADIO_TYPE. - -* added pam_access module (Alexei Nogin) - -* added documentation for pam_lastlog. Also modified the module to - not (by default) print "welcome to your new account" when it cannot - find a utmp entry for the user (you can turn this on with the - "never" argument). - -* small correction to the pam_fail_delay manual page. Either the appl or - the modules header file will prototype this function. - -* added "bigcrypt" (DEC's C2) algorithm(0) to pam_pwdb. (Andy Phillips) - -* *BSD tweaking for various #include's etc. (pam_lastlog, pam_rhosts, - pam_wheel, libpam/pam_handlers). (Michael Smith) - -* added configuration directory $SCONFIGED for module specific - configuration files. - -* added two new "linked" man pages (pam.conf(8) and pam.d(8)) - -* included a reasonable default for /etc/pam.conf (which can be - translated to /etc/pam.d/* files with the pam_conv1 binary) - -* fixed the names of the new configuration files in - conf/pam_conv1/pam_conv.y - -* fixed make check. - -* pam_lastlog fixed to handle UID in virgin part of /var/log/lastlog - (bug report from Ronald Wahl). - -* grammar fix in pam_cracklib - -* segfault avoided in pam_pwdb (getting user). Updating of passwords - that are directed to a "new" database are more robust now (bug noted - by Michael K. Johnson). Added "unix" module argument for migrating - passwords from another database to /etc/passwd. (documentation - updated). Removed "bad username []" warning for empty passwords - - on again if you supply the 'debug' module argument. - -* ctrl-D respected in conversation function (libpam_misc) - -* Removed -DPAM_FAIL_DELAY_ON from top-level Makefile. Nothing in - the distribution uses it. I guess this change happened a while - back, basically I'm trying to make the module parts of the - distribution "source compatible" with the RFC definition of PAM. - This implementation of PAM is a superset of that definition. I have - added the following symbols to the Linux-PAM header files: - - PAM_DATA_SILENT (see _pam_types.h) - HAVE_PAM_FAIL_DELAY (see _pam_types.h) - PAM_DATA_REPLACE (see _pam_modules.h) - - Any module (or application) that wants to utilize these features, - should check (#ifdef) for these tokens before using the associated - functionality. (Credit to Michael K. Johnson for pointing out my - earlier omission: not documenting this change :*) - -* first stab at making modules more independent of full library - source. Modules converted: - pam_deny - pam_permit - pam_lastlog - pam_pwdb - -* pam_env.c: #include added to ease GNU libc use. (Michael - K. Johnson) - -* pam_unix_passwd fixes to shadow aging code (Eliot Frank) - -* added README for pam_tally - -0.57: Fri Apr 4 23:00:45 PST 1997 Andrew Morgan - -* added "nodelay" argument to pam_pwdb. This can be used to turn off - the call to pam_fail_delay that takes effect when the user fails to - authenticate themself. - -* added "suppress" argument to pam_rhosts_auth module. This will stop - printing the "rlogin failure message" when the user does not have a - .rhosts file. - -* Extra fixes for FAKEROOT in Makefiles (Savochkin Andrey - Vladimirovich) - -* pam_tally added to tree courtesy of Tim Baverstock - -* pam_rhosts_auth was failing to read NFS mounted .rhosts - files. (Fixed by Peter Allgeyer). Refixed and further enhanced - (netgroups) by Nicolai Langfeldt. [Credit also to G.Wilford for some - changes that were not actually included..] - -* optional (#ifdef PAM_READ_BOTH_CONFS) support for parsing of pam.d/ - AND pam.conf files (Elliot Lee). - -* Added (and signed) Cristian's PGP key. (I've never met him, but I am - convinced the key belongs to the guy that is making the PAM rpms and - also producing libpwdb. Please note, I will not be signing anyone - else's key without a personal introduction..) - -* fixed erroneous syslog warning in pam_listfile (Savochkin Andrey - Vladimirovich, whole file reformatted by Cristian) - -* modified pam_securetty to return PAM_IGNORE in the case that the user's - name is not known to the system (was previously, PAM_USER_UNKNOWN). The - Rationale is that pam_securetty's sole purpose is to prevent superuser - login anywhere other than at the console. It is not its concern that the - user is unknown - only that they are _not_ root. Returning - PAM_IGNORE, however, insures that the pam_securetty can never be used to - "authenticate" a non-existent user. (Cristian Gafton with bug report from - Roger Hu) - -* Modified pam_nologin to display the no-login message when the user - is not known. The return value in this case is still PAM_USER_UNKNOWN. - (Bug report from Cristian Gafton) - -* Added NEED_LCKPWD for pam_unix/ This is used to define the locking - functions and should only be turned on if you don't have them in - your libc. - -* tidied up pam_lastlog and pam_pwdb: removed function that was never used. - -* Note for package maintainers: I have added $(FAKEROOT) to the list of - environment variables. This should help greatly when you build PAM - in a subdirectory. I've gone through the tree and tried to make - everything compatible with it. - -* added pam_env (courtesy of Dave Kinchlea) - -* removed pam_passwd+ from the tree. It has not been maintained in a - long time and running a shell script was basically insecure. I've - indicated where you can pick up the source if you want it. - -* #define HAVE_PAM_FAIL_DELAY . Applications can conditionally compile - with this if they want to see if the facility is available. It is - now always available. (corresponding compilation cleanups..) - -* _pam_sanitize() added to pam_misc. It purges the PAM_AUTHTOK and - PAM_OLDAUTHTOK items. (calls replaced in pam_auth and pam_password) - -* pam_rhosts now knows about the '+' entry. Since I think this is a - dangerous thing, I have required that the sysadmin supply the - "promiscuous" flag for it in the corresponding configuration file - before it will work. - -* FULL_LINUX_PAM_SOURCE_TREE exported from the top level make file. - If you want to build a module, you can test for this to determine if - it should take its directions from above or supply default locations - for installation. Etc. - -0.56: Sat Feb 15 12:21:01 PST 1997 - -* pam_handlers.c can now interpret the pam.d/ service config tree: - - if /etc/pam.d/ exists /etc/pam.conf is IGNORED - (otherwise /etc/pam.conf is treated as before) - - given /etc/pam.d/ - . config files are named (in lower case) by service-name - . config files have same syntax as /etc/pam.conf except - that the "service-name" field is not present. (there - are thus three manditory fields (and arguments are - optional): - - module-type control-flag module-path optional-args... - - ) - -* included conf/pam_conv1 for converting pam.conf to a pam.d/ version - 1.0 directory tree. This program reads a pam.conf file on the - standard input stream and creates ./pam.d/ (in the local directory) - and fills it with ./pam.d/"service-name" files. - - *> Note: It will fail if ./pam.d/ already exists. - - PLEASE REPORT ANY BUGS WITH THIS CONVERSION PROGRAM... It currently - cannot retain comments from the old conf file, so take care to do this - by hand. Also, please email me with the fix that makes the - shift/reduce conflict go away... - -* Added default module path to libpam for modules (see pam_handlers.c) - it makes use of Makfile defined symbol: DEFAULT_MODULE_PATH which is - inhereted from the defs/* variable $(SECUREDIR). Removed module - paths from the sample pam.conf file as they are no longer needed. - -* pam_pwdb can now verify read protected passwords when it is not run - by root. This is via a helper binary that is setuid root. - -* pam_permit now prompts for a username if it is not already determined - -* pam_rhosts now honors "debug" and no longer hardwire's "root" as the - superuser's name. - -* pam_securetty now honors the "debug" flag - -* trouble parsing extra spaces fixed in pam_time and pam_group - -* added Michael K. Johnson's PGP key to the pgp.keys.asc list - -* pam_end->env not being free()'d: fixed - -* manuals relocated to section 3 - -* fixed bug in pam_mail.c, and enhanced to recognize '~' as a prefix - to indicate the $HOME of the user (courtesy David - Kinchlea). *Changed* from a "session" module to an "auth" - module. It cannot be used to authenticate a user, but it can be used - in setting credentials. - -* fixed a stupid bug in pam_warn.. Only PAM_SERVICE was being read :*( - -* pam_radius rewritten to exclusively make use of libpwdb. (minor fix - to Makefile for cleaning up - AGM) - -* pam_limits extended to limit the total number of logins on a system - at any given time. - -* libpam and libpam_misc use $(MAJOR_REL) and $(MINOR_REL) to set their - version numbers [defined in top level makefile] - -* bugfix in sed command in defs/redhat.defs (AGM's fault) - -* The following was related to a possibility of buffer overruns in - the syslogging code: removed fixed length array from syslogging - function in the following modules [capitalized the log identifier - so the sysadmin can "know" these are fixed on the local system], - - pam_ftp, pam_stress, pam_rootok, pam_securetty, - pam_listfile, pam_shells, pam_warn, pam_lastlog - and - pam_unix_passwd (where it was definitely _not_ exploitable) - -0.55: Sat Jan 4 14:43:02 PST 1997, Andrew Morgan - -* added "requisite" control_flag to /etc/pam.conf syntax. [See - Sys. Admin. Guide for explanation] changes to pam_handlers.c - -* completely new handling of garbled pam.conf lines. The modus - operandi now is to assume that any errors in the line are minor. - Errors of this sort should *most definitely* lead to the module - failing, however, just ignoring the line (as was the case - previously) can lead to gaping security holes(! Not foreseen by the - RFC). The "motivation" for the RFC's comments about ignoring garbled - lines is present in spirit in the new code: basically a garbled line - is treated like an instance of the pam_deny.so module. - changes to pam_handlers.c and pam_dispatch.c . - -* patched libpam, to (a) call _pam_init_handlers from pam_start() and - (b) to log a text error if there are no modules defined for a given - service when a call to a module is requested. [pam_start() and - pam_dispatch() were changed]. - -* patched pam_securetty to deal with "/dev/" prefix on PAM_TTY item. - -* reorganized the modules/Makefile to include *ALL* modules. It is now - the responsibility of the modules themselves to test whether they can - be compiled locally or not. - -* modified pam_group to add to the getgroups() list rather than overwrite - it. [In the case of "HAVE_LIBPWDB" we use the pwdb_..() calls to - translate the group names.]. Module now pays attention to - PAM_CRED_.. flag(!) - -* identified and removed bugs in field reading code of pam_time and - (thus) pam_group. - -* Cristian's patches to pam_listfile module, corresponding change to - documentation. - -* I've discovered &ero; for sgml! - Added pam_time documentation to the admin guide. - -* added manual pages: pam.8, pam_start.2(=pam_end.2), - pam_authenticate.2, pam_setcred.2, pam_strerror.2, - pam_open_session.2(=pam_close_session.2) and pam_chauthtok.2 . - -* added new modules: - - - pam_mail (tells the user if they have any new mail - and sets their MAIL env variable) - - pam_lastlog (reports on the last time this user called - this module) - -* new module hooks provided. - -* added a timeout feature to the conversation function in - libpam_misc. Documented it in the application developers' guide. - -* fixed bug in pam_misc_paste_env() function.. - -* slight modifications to wheel and rhosts writeup. - -* more security issues added to module and application guides. - --- -Things present but not mentioned in previous release (sorry) - -* pam_pwdb module now resets the "last_change" entry before updating a - password. --- - -Sat Nov 30 19:30:20 PST 1996, Andrew Morgan - -* added environment handling to libpam. involved change to _pam_types.h - also added supplementary functions to libpam_misc - -* added pam_radius - Cristian - -* slight speed up for pam_rhosts - -* significantly enhanced sys-admin documentation (8 p -> 41 p in - PostScript). Added to other documentation too. Mostly the changes - in the other docs concern the new PAM-environment support, there is - also some coverage of libpam_misc in the App. Developers' guide. - -* Cristian's patches to pam_limits and pam_pwdb. Fixing bugs. (MORE added) - -* adopted Cristian's _pam_macros.h file to help with common macros and - debugging stuff, gone through tree tidying up debugging lines to use - this [not complete]. - - - for consistency replaced DROP() with _pam_drop() - -* commented memory debugging in top level makefile - -* added the following modules - - - pam_warn log information to syslog(3) about service application - - pam_ftp if user is 'ftp' then set PAM_RUSER/PAM_RHOST with password - (comment about nologin added to last release's notes) - -* modified the pam_listfile module. It now declares a meaningful static - structure name. - -Sun Nov 10 13:26:39 PST 1996, Andrew Morgan - - **PLEASE *RE*AMEND YOUR PERSONAL LINKS** - - -------> http://parc.power.net/morgan/Linux-PAM/index.html <------- - - **PLEASE *RE*AMEND YOUR PERSONAL LINKS** - -A brief summary of what has changed: - -* many modules have been modified to accomodate fixing the pam_get_user() - change. Please take note if you have a module in this distribution. - -* pam_unix is now the pam_unix that Red Hat has been using and which - should be fairly well debugged. - - - I've added some #ifdef's to make it compile for me, and also - updated it with respect to the libpam-0.53, so have a look at the - .../modules/pam_unix/Makefile to enable cracklib and shadow features - - ** BECAUSE OF THIS, I cannot guarantee this code works as it ** - ** did for Red Hat. Please test and report any problems. ** - -* the pam_unix of .52 (renamed to pam_pwdb) has been enhanced and made - more flexible with by implementing it with respect to the new - "Password Database Library" see - - http://parc.power.net/morgan/libpwdb/index.html - - modules included in this release that require this library to - function are the following: - - - pam_pwdb (ne pam_unix-0.52 + some enhancements) - - pam_wheel - - pam_limits - - pam_nologin - -* Added some optional code for memory debugging. In order to support - this you have to enable MEMORY_DEBUG in the top level makefile and - also #define MEMORY_DEBUG in your applications when they are compiled. - The extra code resides in libpam (compiled if MEMORY_DEBUG is defined) - and the macros for malloc etc. are to be found at the end of - _pam_types.h - -* used above code to locate two memory leaks in pam_unix module and two - in libpam (pam_handlers.h) - -* pam_get_user() now sets the PAM_USER item. After reading the Sun - manual page again, it was clear that it should do this. Various - modules have been assuming this and now I have modified most of them - to account for this change. Additionally, pam_get_user() is now - located in the module include file; modules are supposed to be the - ones that use it(!) [Note, this is explicitly contrary to the Sun - manual page, but in the spirit of the Linux distribution to date.] - -* replaced -D"LINUX" with -D"LINUX_PAM" as this is more explicit and less - likely to be confused with -D"linux". - Also, modified the libpam #include files to behave more like the Sun - ones #ifndef LINUX_PAM. - -* removed - -0. Before I begin, Linux-PAM has a new primary distribution site (kindly -donated by Power Net Inc., Los Angeles) - - **PLEASE AMMEND YOUR PERSONAL LINKS** - - -------> http://www.power.net/morgan/Linux-PAM <------- - - **PLEASE AMMEND YOUR PERSONAL LINKS** - -1. I'm hoping to make the next release a bug-fix release... So please find - all the bugs(! ;^) - -2. here are the changes for .52: - -* minor changes to module documentation [Incidently, it is now - available on-line from the WWW page above]. More changes to follow in - the next two releases. PLEASE EMAIL me or the list if there is - anything that isn't clear! - -* completely changed the unix module. Now a single module for all four - management groups (this meant that I could define all functions as - static that were not part of the pam_sm_... scheme. AGM) - - - Shadow support added -PASSWD - Elliot's account management included, and enhanced by Cristian Gafton. - - MD5 password support added by Cristian Gafton. - - maxtries for authentication now enforced. - - Password changing function in pam_unix now works! - Although obviously, I'm not going to *guarantee* it ;^) . - - stole Marek's locking code from the Red Hat unix module. - [ If you like you can #ifdef it in or out ... ] - - You can configure the module more from its Makefile in - 0.52/modules/pam_unix/ - - If you are nervous that it will destroy your /etc/passwd or shadow - files then EDIT the 0.52/modules/pam_unix/pam_unix_pass.-c file. - Here is the warning comment from this file... - --------------8<----------------- -/* - * - * Uncomment the following #define if you are paranoid, and do not - * want to risk losing your /etc/passwd or shadow files. - * It works for me (AGM) but there are no guarantees. - * - * - */ -/* #define TMP__FILE */ -------------->8----------------- - - *** If anyone has any trouble, please *say*. Your problem will be - fixed in the next release. Also please feel free to scour the - code for race conditions etc... - -[* The above change requires that you purge your /usr/lib/security - directory of the old pam_unix_XXX.so modules: they will NOT be deleted - with a 'make remove'.] - -* the prototype for the cleanup function supplied to pam_set_data used - to return "int". According to Sun it should be "void". CHANGED. - -* added some definitions for the 'error_status' mask values that are - passed to the cleanup function associated with each - module-data-item. These numbers were needed to keep up with changing - a data item (see for example the code in pam_unix/support.-c that - manages the maximum number of retries so far). Will see what Sun says - (current indications are positive); this may be undone before 1.0 is - released. Here are the definitions (from pam_modules.h). - -#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */ -#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */ - -* Changed the .../conf/pam.conf file. It now points to the new - pam_unix module for 'su' and 'passwd' [can get these as SimpleApps -- - I use them for testing. A more extensive selection of applications is - available from Red Hat...] - -* corrected a bug in pam_dispatch. Basically, the problem was that if - all the modules were "sufficient" then the return value for this - function was never set. The net effect was that _pam_dispatch_aux - returned success when all the sufficient modules failed. :^( I think - this is the correct fix to a problem that the Red Hat folks had - found... - -sopwith* Removed advisory locking from libpam (thanks for the POSIX patch - goes to Josh Wilmes's, my apologies for not using it in the - end.). Advisory locking did not seem sufficiently secure for libpam. - Thanks to Werner Almesberger for identifying the corresponding "denial - of service attack". :*( - -* related to fix, have introduced a lock file /var/lock/subsys/PAM - that can be used to indicate the system should pay attention to - advisory locking on /etc/pam.conf file. To implement this you need to - define PAM_LOCKING though. (see .52/libpam) - -* modified pam_fail_delay() function. Couldn't find the "not working" - problem indicated by Michael, but modified it to do pseudo-random - delays based on the values indicated by pam_fail_delay() -- the - function "that may eventually go away"... Although Sun is warming to - the idea. - -* new modules include: - - pam_shells - authentication for users with a shell listed in - /etc/shells. Erik Troan - - pam_listfile - authentication based on the contents of files. - Set to be more general than the above in the - future. UNTESTED. Elliot Lee <@redhat.com> - [Note, this module compiles with a non-trivial - warning: AGM] - -Thu Aug 8 22:32:15 PDT 1996 (Andrew Morgan ) - -* modified makefiles to take more of their installation instructions - from the top level makefile. Desired for integration into the Debian - distribution, and generally a good idea. - -* fixed memory arithmetic in pam_handlers - -- still need to track down why failure to load modules can lead to - authentication succeding.. - -* added tags for new modules (smartcards from Alex -- just a promise - at this stage) and a new module from Elliot Lee; pam_securetty - -* I have not had time to smooth out the wrinkles with it, but Alex's - pam_unix modifications are provided in pam_unix-alex (in the modules - directory) they will not be compiled by 'make all' and I can't even - say if they do compile... I will try to look at them for .52 but, in - the mean time please feel free to study/fix/discuss what is there. - -* pam_rhosts module. Removed code for manually setting the ruser - etc. This was not very secure. - -* [remade .ps docs to be in letter format -- my printer complains - about a4] - -Sunday July, 7 12:45:00 PST 1996 (Andrew Morgan ) - -* No longer accompanying the Linux-PAM release with apps installed. - [Will provide what was here in a separate package.. (soon) -lib Also see http://www.redhat.com/pam for some more (in .rpm form...)] - -* renamed libmisc to libpam_misc. It is currently configured to only compile - the static library. For some strange reason (perhaps someone can - investigate) my Linux 2.0.0 kernel with RedHat 3.0.3 system - segfaults when I compile it to be a dynamic library. The segfault - seems to be inside the call to the ** dl_XXX ** function...!? - - There is a simple flag in the libpam_misc/Makefile to turn on dynamic - compiles. - -* Added a little unofficial code for delay support in libpam (will probably - disappear later..) There is some documentation for it in the pam_modules - doc now. That will obviously go too. - -* rewritten pam_time to use *logic* to specify the stringing together of - users/times/terminals etc.. (what was there before was superficially - logical but basically un-predictable!) - -* added pam_group. Its syntax is almost identical to pam_time but it - has another field added; a list of groups to make the user a member - of if they pass the previous tests. It seems to not co-exist too well - with the groups in the /etc/group but I hope to have that fixed by - the next release... - -* minor re-formatting of pam_modules documentation - -* removed ...// since it wasn't being used and didn't look like it - would be! - -GCCSunday 23 22:35:00 PST 1996 (Andrew Morgan ) - -* The major change is the addition of a new module: pam_time for - restricting access on terminals at given times for indicated users - it comes with its own configuration file /etc/security/time.conf - and the sample file simply restricts 'you' from satisfying the blank - application if they try to use blank from any tty* - -* Small changes include -- altered pam.conf to demonstrate above new module (try typing username: you) -- very minor changes to the docs (pam_appl and pam_modules) - -Saturday June 2 01:40:00 PST 1996 (Andrew Morgan ) - -*** PLEASE READ THE README, it has changed *** - -* NOTE, 'su' exhibits a "system error", when static linking is - used. This is because the pam_unix_... module currently only has - partial static linking support. This is likely to change on Monday - June 3, when Alex makes his latest version availible. I will include - the updated module in next release. - -changes for .42: - -* modified the way in which libpam/pam_modules.h defines prototypes for - the pam_sm_ functions. Now the module must declare which functions it - is to provide *before* the #include line. - (for contrasting examples, see the pam_deny and pam_rootok modules) - This removed the ugly hack of defining functions that are never called - to overcome warnings... This seems much tidier. -insterted* updated the TODO list. (changed mailing list address) -* updated README in .../modules to reflect modifications to static - compliation protocol -* modified the pam_modules documentation to describe this. -* corrected last argument of pam_get_item( ... ) in - pam_appl/modules.sgml, to "const void **". -* altered GNU GPL's in the documentation, and various other parts of - the distribution. *Please check* that any code you are responsible for - is corrected. -* Added ./Copyright (please check that it is acceptable) -* updated ./README to make current and indicate the new mailing list - address -* have completely rewritten pam_filter. It now runs modular filter - executables (stored in /usr/sbin/pam_filter/) This should make it - trivial for others to write their own filters.. If you want yours - included in the distribution please email the list/me. -* changes to libpam; there was a silly bug with multiple arguments on a - pam.conf line that was broken with a '\'. -* 'su' rearranged code (to make better use of PAM) - *Also* now uses POSIX signals--this should help the Alpha port. -* 'passwd' now uses getlogin() to determine who's passwords to change. - -Sunday May 26 9:00:00 PST 1996 (Andrew Morgan ) - -* fixed module makefiles to create needed dynamic/static subdirectories - -Saturday May 25 20:30:27.8 PST 1996 (Andrew Morgan ) - -* LOTS has changed regarding how the modules/libpam are built. -* Michael's mostly complete changes for static support--see below - (Andrew got a little carried away and automated the static linking - of modules---bugs are likely mine ;( ) -* Thanks mostly to Michael, libpam now compiles without a single warning :^] -* made static modules/library optional. -CFLAGS* added 'make sterile' to top level makefile. This does extraclean and remove -* added Michael and Joseph to documentation credits (and a subsection for - future documentation of static module support in pam_modules.sgml) -* libpam; many changes to makefiles and also automated the inclusion of - static module objects in pam_static.c -* modified modules for automated static/dynamic support. Added static & - dynamic subdirectories, as instructed by Michael -* removed an annoying syslog message from pam_filter: "parent exited.." -* updated todo list (anyone know anything about svgalib/X? we probably should - have some support for these...) - -Friday May 24 16:30:15 EDT 1996 (Michael K. Johnson ) - -* Added first (incomplete) cut at static support. - This includes: - . changes in libpam, including a new file, pam_static.c - . changes to modules including exporting struct of function pointers - . static and dynamic linking can be combined - . right now, the only working combinations are just dynamic - linking and dynamic libpam.so with static modules linked - into libpam.so. That's on the list of things to fix... - . modules are built differently depending on whether they - are static or dynamic. Therefore, there are two directories - under each module directory, one for static, and one for - dynamic modules. -* Fixed random brokenness in the Makefiles. [ foo -nt bar ] is - rather redundant in a makefile, for instance. Also, passing - on the command line is broken because it cannot be - overridden in any way (even adding important parts) in lower-level - makefiles. -* Unfortunately, fixing some of the brokenness meant that I used - GNU-specific stuff. However, I *think* that there was GNU-specific - stuff already. And I think that we should just use the GNU - extensions, because any platform that GNU make doesn't port to - easily will be hard to port to anyway. It also won't be likely -passwd to handle autoconf, which was Ted's suggestion for getting - around limitations in standard make... - For now, I suggest that we just use some simple GNU-specific - extensions. - -Monday May 20 22:00:00 PST 1996 (Andrew Morgan ) - -* added some text to pam_modules.sgml -* corrected Marek's name in all documentation -* made pam_stress conform to chauthtok conventions -- ie can now request - old password before proceeding. -* included Alex's latest unix module -* included Al's + password strength checking module -* included pam_rootok module -* fixed too many bugs in libpam.. all subtly related to the argument lists - or use of syslog. Added more debugging lines here too. -* fixed the pam.conf file -* deleted pam_test module. It is pretty old and basically superceeded - by pam_stress - -Friday May 9 1:00:00 PST 1996 (Andrew Morgan ) - -* updated documentaion, added Al Longyear to credits and corrected the - spelling of Jeff's name(!). Most changes to pam.sgml (even added a figure!) -* new module pam_rhosts_auth (from Al Longyear) -* new apps rlogind and ftpd (a patch) from Al. -* modified 'passwd' to not call pam_authenticate (note, none of the - modules respect this convention yet!) -* fixed bug in libpam that caused trouble if the last line of a - pam.conf file ends with a module name and no newline character -* also made more compatable with documentation, in that bad lines in - pam.conf are now ignored rather than causing libpam to return an - error to the app. -* libpam now overwrites the AUTHTOKs when returning from - pam_authenticate and pam_chauthtok calls (as per Sun/RFC too) -* libpam is now installed as libpam.so.XXX in a way that ldconfig can - handle! - - -Wednesday May 1 22:00:00 PST 1996 (Andrew Morgan ) - -* removed .../test directory, use .../examples from now on. -* added .../apps directory for fully functional applications - - the apps directory contains directories that actually contain the apps. - the idea is to make application compilation conditional on the presence - of the directory. Note, there are entries in the Makefile for - 'login' and 'ftpd' that are ready for installation... Email me if - you want to reserve a directory name for an application you are - working on... -* similar changes to .../modules makefile [entries for pam_skey and - pam_kerberos created---awaiting the directories.] Email me if you - want to register another module... -* minor changes to docs.. Not really worth reprinting them quite yet! - [save the trees] -* added misc_conv to libmisc. it is a generic conversation function - for text based applications. [would be nice to see someone create - an Xlib and/or svgalib version] -* fixed ctrl-z/c bug with pam_filter module [try xsh with the default - pam.conf file] -* added 'required' argument to 'pam_stress' module. -* added a TODO list... other suggestions to the list please. - -Saturday April 7 00:00:00 PST 1996 ( Andrew Morgan ) - -* Alex and Marek please note I have altered _pam_auth_unix a little, to - make it get the passwords with the "proper method" (and also fixed it - to not have as many compiler warnings) -* updated the conf/pam.conf file -* added new example application examples/xsh.c (like blank but invokes - /bin/sh) -* Marc's patches for examples/blank.c (and AGM's too) -* fixed stacking of modules in libpam/pam_handlers.c -* fixed RESETing in libpam/pam_item.c -* added new module modules/pam_filter/ to demonstrate the possibility - of inserting an arbitrary filter between the terminal and the - application that could do customized logging etc... (see use of - bin/xsh as defined in conf/pam.conf) - - -Saturday March 16 19:00:00 PST 1996 ( Andrew Morgan ) - -These notes are for 0.3 I don't think I've left anything important -out, but I will use emacs 'C-x v a' next time! (Thanks Jeff) - - * not much has changed with the functionality of the Linux-PAM lib - .../libpam - - pam_password calls module twice with different arguments - - added const to some of the function arguments - - added PAM_MAX_MES_ to - - was a lot over zealous about purging old passwords... - I have removed much of this from source to make it - more compatible with SUN. - - moved some PAM_... tokens to pam_modules.h from _pam_types.h - (no-one should notice) - - * added three modules: pam_permit pam_deny pam_stress - no prizes for guessing what the first two do. The third is - a reasonably complete (functional) module. Is intended for testing - applications with. - - * fixed a few pieces of examples/blank.c so that it works (with - pam_stress) - - * ammended the documentation. Looking better, but suggestions/comments - very welcome! - -Sunday March 10 10:50:00 PST 1996 ( Andrew Morgan ) - -These notes are for Linux-PAM release 0.21. They cover what's changed -since I relased 0.2. - - * am now using RCS - * substantially changed ./README - * fixed bug reading \\\n in pam.conf file - * small changes to documentation - * added `blank' application to ./examples (could be viewed as - a `Linux-PAM aware' application template.) - * oops. now including pam_passwd.o and pam_session.o in pamlib.so - * compute md5 checksums for all the source when making a release - - added `make check' and `make RCScheck' to compute md5 checksums - * create a second tar file with all the RCS files in. - * removed the .html and .txt docs, supplying sgml sources instead. - - see README for info on where to get .ps files - -Thursday March 6 0:44:?? PST 1996 ( Andrew Morgan ) - -These notes are for Linux-PAM release 0.2. They cover what's changed -since Marc Ewing relased 0.1. - -**** Please note. All of the directories in this release have been modified -**** slightly to conform to the new pamlib. A couple of new directories have -**** been added. As well as some documentation. If some of your code -**** was in the previous release. Feel free to update it, but please -**** try to conform to the new headers and Makefiles. - -* Andrew Morgan (morgan@physics.ucla.edu) is making this release - availible, Marc has been busy...! - -* Marc's pam-0.1/lib has been (quietly) enhanced and integrated into - Alex Yurie's collected tree of library and module code - (linux-pam.prop.1.tar.gz). Most of the changes are to do with error - checking. Some more robustness in the reading of the pam.conf file - and the addition of the pam_get_user() function. - -* The pam_*.h files have been reorganized to logically enforce the - separation of modules from applications. [Don't panic! Apart from - changing references of the form - - #include "pam_appl.h" - - to - - #include - - The reorganization should be backwardly compatable (ie. a module - written for SUN will be as compatable as it was before with the - previous version ;)~ ] - - (All of the source in this tree now conforms to this scheme...) - - The new reorganization means that modules can be compiled with a - single header, , and applications with - . - -* I have tried to remove all the compiler warnings from the updated - "pamlib/*.c" files. On my system, (with a slightly modified - email me if it interests you..) there are only two warnings that - remain: they are that ansi does not permit void --> fn ptr - assignment. K&Rv2 doesn't mention this....? As a matter of principle, - if anyone knows how to get rid of that warning... please - tell. Thanks! "-pedantic" - -* you can "make all" as a plain user, but - -* to "make install" you must be root. The include files are placed in - /usr/include/security. The libpam.so library is installed in /usr/lib - and the modules in /usr/lib/security. The two test binaries - are installed in the Linux-PAM-0.2/bin directory and a chance is given to - replace your /etc/pam.conf file with the one in Linux-PAM-0.2/conf. - -* I have included some documentation (pretty preliminary at the -moment) which I have been working on in .../doc . - -I have had a little trouble with the modules, but atleast there are no -segfaults! Please try it out and discuss your results... I actually -hope it all works for you. But, Email any bugs/suggestions to the -Linux-PAM list: linux-pam@mit.edu ..... - -Regards, - -Andrew Morgan -(morgan@physics.ucla.edu) - - -Sat Feb 17 17:30:24 EST 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu) - - * conf directory created with example of pam_conf - * stable code from pam_unix is added to modules/pam_unix - * test/test.c now requests username and password and attempts - to perform authentication - diff --git a/Copyright b/Copyright deleted file mode 100644 index 2f27a2ee..00000000 --- a/Copyright +++ /dev/null @@ -1,41 +0,0 @@ -Unless otherwise *explicitly* stated the following text describes the -licensed conditions under which the contents of this Linux-PAM release -may be distributed: - -------------------------------------------------------------------------- -Redistribution and use in source and binary forms of Linux-PAM, with -or without modification, are permitted provided that the following -conditions are met: - -1. Redistributions of source code must retain any existing copyright - notice, and this entire permission notice in its entirety, - including the disclaimer of warranties. - -2. Redistributions in binary form must reproduce all prior and current - copyright notices, this list of conditions, and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -3. The name of any author may not be used to endorse or promote - products derived from this software without their specific prior - written permission. - -ALTERNATIVELY, this product may be distributed under the terms of the -GNU General Public License, in which case the provisions of the GNU -GPL are required INSTEAD OF the above restrictions. (This clause is -necessary due to a potential conflict between the GNU GPL and the -restrictions contained in a BSD-style copyright.) - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -------------------------------------------------------------------------- - diff --git a/Linux-PAM/CHANGELOG b/Linux-PAM/CHANGELOG new file mode 100644 index 00000000..f187f0f7 --- /dev/null +++ b/Linux-PAM/CHANGELOG @@ -0,0 +1,1582 @@ + +$Id: CHANGELOG,v 1.1.1.2 2002/09/15 20:08:18 hartmans Exp $ + +----------------------------- + +TODO: + + - sanitize use of md5 throughout distribution.. Make a static + library for helping to develop modules that contains it and other + stuff. Also add sha-1 and ripemd-160 digest algorithms. + - once above is done. remove hacks from the secret@here module etc.. + - remove prototype for gethostname in pam_access.c (Derrick) + - document PAM_INCOMPLETE changes + - verify that the PAM_INCOMPLETE interface is sensible. Can we + catch errors? should we permit item changing etc., between + pam_authenticate re-invocations? + - verify that the PAM_INCOMPLETE interface works (auth seems ok..) + - add PAM_INCOMPLETE support to modules (partially added to pam_pwdb) + - work on RFC. + - do we still need to remove openlog/closelog from modules..? + - auth and acct support in pam_cracklib, "yes, I know the password + you just typed was valid, I just don't think it was very strong..." + - add in the pam_cap and pam_netid modules + +==================================================================== +Note, as of release 0.73, all checkins should be accompanied with a +Bug ID. The bug IDs relate to sourceforge IDs.. (Of course, nothing is +ever that simple. It turns out that at some point in Sourceforge's +history all of the bug ids got bumped by 100000, so pretty much if you +see a bug ID below that begins with a '1' and your attempted query +fails, try adding 100000 to the number and trying again. I believe +this only affects bugs before release 0.76.) + +You can query the related bug description with the following URL: + + http://sourceforge.net/tracker/index.php?func=detail&aid=XXXXXX&group_id=6663&atid=106663 + +Where you should replace XXXXXX with a bug-id. + +For general documentation completion work, I'm doing it all with +respect to specific tasks. Open tasks are listed here: + + http://sourceforge.net/pm/task.php?group_id=6663&group_project_id=2741&func=browse&set=open + +If you have found a bug in Linux-PAM (including a documentation bug, +or a new feature request and/or patch), please consider filing such a +bug report - outstanding bugs are listed here: + + http://sourceforge.net/tracker/?atid=106663&group_id=6663&func=browse + +(to file another bug see the 'submit bug' button on that page). + +==================================================================== + +0.76: please submit patches for this section with actual code/doc + patches! + +* pam_unix: fix for legacy crypt() support when the password entered + was long. (Bug 521314 - agmorgan). +* pam_access no longer include gethostname() prototype complained from + David Lee (Bug 415423 - agmorgan). +* make pam_nologin more secure by default, added two new module + arguments etc. - acting on suggestion from Nico (Bug 419307 - + agmorgan) +* link in libpam to libpam_misc - since the latter uses functions in + the former it makes some sort of sense to do this (although, in the + static library case, I remain to be convinced). (Bug 565470 - + agmorgan). +* absorbed some of the proposed darwin (OS X) changes from Luke Howard + (of PADL software) - hopefully will get the rest (see Rob Braun's + 534205) by 0.77 (Bug 491466 - agmorgan). +* README fix for pam_unix from Nalin (Bug 476971 - agmorgan). +* add support for building pdf files from the documentation - request + from 'lolive' (Bug 471377 - agmorgan). +* documented the equivalent '[..]' expressions for "required" + etc. Request from Ross Patterson (Bug 529078 - agmorgan). +* '[...]' parsing: document it and also fix it to support '\]' escape + sequence. Feature request from Russell Kliese (Bug 517064 - + agmorgan). +* pam_rootok: compilation warning noted by Tony den Haan wrt no + prototype for strcmp() (Bug 557322 - agmorgan). +* documentation: (a few of mine in passing) and app documentation + suggestions regarding PAM environment variables and module + documentation changes regarding the conversation function from Jenn + Vesperman (Bug 527821, 527965 - agmorgan) +* documentation: pam_time.sgml typo fixed, pam_motd exists now, + correct Red Hat comment about config files (Bugs 554274, 554261, + 554182 - agmorgan) +* pam_limits: added '%' domain for maxlogins limiting, now '*' and @group + have the old meaning (every) and '%' the new one (all) + (Bug 533664 - baggins) +* pam_limits: put not so interesting log messages under debug arg + (Bug 533668 - baggins) +* pam_access: added the 'fieldsep=' argument (Bug 547051 - agmorgan), + made a PAM_RHOST of "" equivalent to NULL (Bug 547521 - agmorgan). +* pam_limits: keep well know behaviour of maxlogins default ('*') limit + (Bug 533664 - baggins) +* pam_unix: more from Nalin log password changes (Bug 517743 - agmorgan) +* pam_limits: make it use the priority value specified in config + (bug 530428 - baggins) +* pam_unix: removed broken code in password update code. Report from + Len Lattanzi (Bug 507379 - agmorgan) +* pam_mkhomedir: recurse directories. Patch from Nalin (Bug 476981 - + agmorgan) +* pam_limits can handle negative priority limits now (which can apply + to the superuser too) - based on patch from Nalin. Also cleanup the + error handling that was very sloppy before. Also, courtesy of Berend + De Schouwe get the math right on login counting (Bug 476990, 476987, + 493294 - agmorgan) +* documentation: random typo fixes from Nalin and more stuff from me + (Bug 476949, Tasks 43507, 17426 - agmorgan) +* A Tru64 fix (given other stuff has already resolved this, it + actually just a comment actually) from 'Eddie'. (Bug 418450 - + agmorgan) +* pam_handlers: BSD fix from Dag-Erling Smørgrav and Anton Berezin + (Bug 486063 - agmorgan) +* added the dynamic/* directory to the distribution. If you go in + there after building the rest of the tree, you'll make a pam.so + object that can be used by something like a java runtime with + dlopen. Its not very well tested - caveat emptor. (Bug 232194 - + agmorgan) +* somehow pam_unix has started forcing the user prompt to be "login: ". + This is entirely inapropriate as it overrides PAM_USER_PROMPT. (Bug + 486361 - agmorgan). +* added a static module helper library object includes a few changes + to examples/xsh.c for testing purposes (added a simple shell wrapper + for running xsh with the sandbox libraries), and also modified the + pam_rhosts_auth module to use this new library. (Bug 490938, 409852 + - agmorgan). +* pam_unix: fix 'likeauth' to kill off the memory leak once and for all. + (Bug 483959 - vorlon) +* pam_unix: restore handling of 'likeauth' argument to a known working + state; prettify AUTH_RETURN macro; remove redundant argv checks in + pam_sm_setcred() (Bugs 483959, 113596 - vorlon) +* pam_cracklib: another try at implementing similar() from Harald + Welte and Nalin (Bugs 436053, 476957 - agmorgan) +* pam_access: default access.conf file contained a type (console + instead of LOCAL) fix from Nalin (Bug 476934 - agmorgan) +* pam_unix: fixed bizarre memory leak pointed out by Fernando Trias + (Bug 483959 - agmorgan) +* misc string comparison length checking changes from Nalin. Modules + touched, pam_cracklib, pam_listfile, pam_unix, pam_wheel (Bug 476947 - + agmorgan) +* pam_userdb: require that all of typed password matches that in + database report and fix from Vladimir Pastukhov. (Bug 484252 - agmorgan) +* pam_malloc: revived malloc debugging code, now tied to + --enable-memory-debug and added strdup() support (Bug 485454 - agmorgan) +* pam_tally: Nalin's fix for lastlog corruption (Bug 476985 - agmorgan) +* pam_rhosts: Nalin adds support for '+hostname', and zdd fix + compilation warning. (Bug 476986 - agmorgan) +* pam_motd: Nalin fixed compiler warning. (Bug 476938 - agmorgan) +* pam_pwdb: Solar Designer pointed out that there was a problem with + the compatibility support for md5 password hashing. (Bug 460717, + 476961 - agmorgan) +* pam_issue: Nalin found segfaulting problems if the PAM_USER_PROMPT + is unset, found some similar problems with assumptions about + realloc. (Bug 476983 - agmorgan) +* pam_env: 'weichangyang of hotmail' pointed out a wild string with no + valid '\0' was leading to problems with sshd and suggested fix (Bug + 473034 - agmorgan) +* MANDIR cleanup. It defaults to /usr/share/man, but can be overridden + using the --enable-mandir ./configure option, similarly for DOCDIR + from Nalin (Bug 476940 - agmorgan) +* pam_filter cleanup (including moving the filter directory) Nalin + and Harald Welte (Bugs 436057, 476970 - agmorgan) +* db3 is now recognized as a libdb candidate (Bug 435764 - agmorgan) +* more changes (extracted from redhat version) courtesy of + Harald Welte (Bugs pam_limits=436061, pam_lastlog=436060, + pam_mkhomedir/pam_env=435991 - agmorgan) +* fix for legacy behavior of pam_setcred and pam_close_session in + the case that pam_authenticate and pam_open_session hadn't been + called - bug report from Seongwan Park. (Bug 468724 - agmorgan) +* some BSD updates and fixes from Mark Murray - including a slightly + more robust conversation function and some minimization of gcc + warnings. (Bugs 449203,463984 - agmorgan) +* verified that the setcred stack didn't suffer from the bug I was + nervous about, add a new module pam_debug to help me test this. + fixed a libpam/pam_dispatch.c instrumentation line that I tripped + over when testing. Also restructured pam_warn to help here (Bug + 424315 - agmorgan). +* pam_unix/support.c: sample use of reentrant NSS function. Not yet active, + because modules do not include _pam_aconf_h! (Bug 440107 - vorlon) +* doc/Makefile changes - use $(mandir) [courtesy Harald Welte] (Bug + 435760) and add some rules to make/delete the draft rfc I've been + working on (Task 17426 - agmorgan) +* pam_modules.sgml: sourceforge has changed its CVS viewing software + (Bug 460491 - agmorgan) +* pam_unix_passwd: got rid of an annoying warning (Bug 461089 - agmorgan) +* configure.in, _pam_aconf.h.in: set the stage for fully reentrant PAM + modules, with some infrastructure to detect getxxbyxx_r() functions + (Bug 440107 - vorlon) +* pam_unix: removed superfluous use of static variables in md5 and bigcrypt + routines, bringing us a step closer to thread-safeness. Eliminated + some variable indirection along the way. (Bug 440107 - vorlon) +* pam_tally: remove #include of stdlib.h, which isn't needed by anything + found in this module. Can be readded if we find a real need for it at + a later date. (Bug 436432 - vorlon) +* pam_tally: added an #include (was it really needed?) and made the + pam_tally app install (with more pretty printing and a corrected + Makefile dependency) motivated by a (red hat diff) courtesy of Harald + Welte (Bug 436432 - agmorgan) +* configure.in changes to help support non-Linux environments courtesy + of Scott T. Emery (Bug 422563 - agmorgan) +* made a pam_cracklib enhancement to interpret -ve limits in a + sensible fashion contributed by Werner Puschitz (Bug 413162 - + agmorgan) +* another fix for the latest number of rlimits available to pam_limits + (Bug 424060 - agmorgan) +* removed stale link from pam_pwdb documentation (Bug 433460 - agmorgan) +* pam_appl.sgml change - more discussion of choosing a service name + (Bug 417512 - agmorgan) +* more specific linking requirements for -lndbm for pam_userdb - from + David Lee (Bug 417339 - agmorgan) +* a large number of small changes to make AIX support better (Bug + 416229 - agmorgan) +* $(MAKE) instead of 'make' - from Scott T. Emery (Bug 422144 - + agmorgan) +* c++ header fixes for pam_misc.h and pam_client.h - from Alexandre + Sagala (Bug 420270 - agmorgan) +* pam_access fixes - looks out for trailing '.' - from Carlo Marcelo + Arenas Belon (Bug 419631 - agmorgan) +* don't zero out password strings during pam_unix's password changing + function (Bug 419803 - vorlon) +* propagate some definitions to the _pam_aconf.h file - from David Lee + (Bug 415419 - agmorgan) +* solaris GCC OS_CFLAGS change from David Lee (Bug 415412 - agmorgan) +* added a comment to this CHANGELOG to explain why most of the bugids + used below appear not to be known to sourceforge [try adding 100000 + to the bugid number.] (Bug 414943 - agmorgan) +* bumped version numbers and also added support for SONAME defines + that appear not to have survived the great autoconf experiment (Bug + 414669 - agmorgan). + +0.75: Sat Apr 7 23:10:50 PDT 2001 + + ** WARNING ** + +This release contains backwardly incompatible changes to +libpam. Prior versions were buggy - see bugfix for Bug 129775. + + ** WARNING ** + +* made 0.75 release (Bug 414665 - agmorgan) +* pam_pwdb has been removed from the suggested pam.conf template. I've + replaced it with pam_unix. (Bug 227565 - agmorgan) +* pam_limits - Richard M. Yumul reported that " -" didn't + work, first fix suggested by Werner Puschitz (Bug 404953 - agmorgan) +* Nicolay Pelov suggested a simple fix for freebsd support (Bug 407282 + - agmorgan) +* Michel D'HOOGE submitted documentation fixes (Bug 408961 - agmorgan) +* fix for module linking directions (Bug 133545 - agmorgan) +* fix for glibc-2.2.2 compilation of pam_issue (Bug 133542 - agmorgan) +* fix pam_userdb to make and link both .o files it needs - converse() + wasn't being linked! (Bug 132880 - agmorgan) +* added some sys-admin documentation for the pam_tally module (Bug + 126210 - agmorgan). +* added a link to module examples from the module writers doc (Bug + 131192 - agmorgan). +* fixed a small security hole (more of a user confusion issue) with + the unix and pwdb password helper binaries. The beef is described in + the bug report, but no uid change was possible so no-one should + think they need to issue a security bulletin over this one! (Bug + 112540 - agmorgan) +* pam_lastlog needs to be linked with -lutil, also removed ambiguity + from sysadmin guide regarding this module being a 'session' module + (Bug 131549 - agmorgan). +* pam_cracklib needs to be linked with -lcrypt (old password checking) + (Bug 131601 - agmorgan). +* fixes for static library builds and also the examples when linked + with the debugging build of the libraries. (Bug 131783 - agmorgan) +* fixed URL for original RFC to a cached kernel.org file. (Bug 131503 + - agmorgan) +* quoted the $CRACKLIB_DICTPATH test in configure.in (Bug 130130 - + agmorgan). +* improved handling of the setcred/close_session and update chauthtok + stack. *Warning* This is a backwardly incompatable change, but 'more + sane' than before. (Bug 129775 - agmorgan) +* bumped the version number, and added some code to assist in making + documentation releases (Bug 129644 - agmorgan). + +0.74: Sun Jan 21 22:36:08 PST 2001 + +* made 0.74 release (Bug 129642 - agmorgan) +* libpam - cleaned up a few non-static functions to be static and added + support for libpam to enforce things like pam_[gs]et_data() and + AUTHTOK rules for using the API. Also documented pam_[gs]et_item() + a little better including return codes (Bugs 129027, 128576 - + agmorgan). +* pam_access - fixed the non-default config file option (Bug 127561 - + agmorgan) +* pam.8 manual page clarified with respect to the default location for + finding modules, also added some text describing the [...] control + syntax. (Bug 127625 - agmorgan) +* md5.h ia64 fixes for pam_unix and pam_pwdb (Bug 127700 - agmorgan) +* removed requirement for c++ from the configure{.in,} files (Bug + 128298 - agmorgan) +* removed subdirectories from man page redirections (124396 - baggins) +* per David Lee, fixed non-POSIX shell command in modules/pam_filter/Makefile + (Bug 126440 - vorlon) +* modify format of pam_unix log messages to include service name + (Bug 126423 - vorlon) +* prevent pam_unix from logging unknown usernames (Bug 126431 - vorlon) +* changed format of pam_unix 'authentication failure' log messages to make + them clearer and more consistent (Bug 126036 - vorlon) +* improved portability of pam_unix by eliminating Linux-specific utmp + defines in PAM_getlogin() (Bug 125704 - vorlon) +* removed static variables from pam_tally (Bug 117434 - agmorgan) +* added copyright message to pam_access module from original logdaemon + sources (Bug 125022 - agmorgan) +* configure.in - removed the GCC -Wtraditional flag (Bug 124923 - agmorgan) +* pam_mail - use PAM_PATH_MAILDIR as the location of mail spool + (Bug 124397 - baggins) +* _pam_aconf.h.in, configure.in - added PAM_PATH_MAILDIR set via + --with-mailspool=dir option (default is _PAM_MAILDIR if defined + in paths.h otherwise /var/spool/mail (Bug 124397 - baggins) +* removed unnecessary CVS Log tags from all over the source + (Bug 124391 - baggins) +* pam_tally - check for PAM_TTY if PAM_RHOST is not set when writing + to faillog (Bug 124394 - baggins) +* use O_NOFOLLOW if available when opening debug log (Bug 124385 - baggins) +* pam_cracklib - removed comments about pam_unix not working with + pam_cracklib, added information about use_authtok parameter + (Bug 124388 - baggins) +* pam_userdb - fixed wrong definition of struct pam_module (was pam_wheel) + (Bug 124386 - baggins) +* fixed example/Makefile include path (Bug 124187, 127563(?) - agmorgan) +* pam_userdb compiles on RH5x. Also removed circular dependency on + configure.in. Also bumped revision number to 0.74. (Bug 124136 - + agmorgan) + +0.73: Sat Dec 2 00:04:04 PST 2000 + +* updated documentaion revisions and added 'make release' support + to the top level Makefile (Bug 124132 - agmorgan). +* documented Qmail support in pam_mail (Bug 109219 - baggins) +* add change_uid option to pam_limits, and set real uid only if + this option is present (Bug 124062 - baggins) +* pam_limits - set real uid to the user for who we set limits. + (Bug 123972 - baggins) +* removed static variables from pam_limits (thread safe now). (Bug + 117450 - agmorgan). +* removed static variable from pam_wheel (module should be thread safe + now). (Bug 112906 - agmorgan) +* added support for '/' symbols in pam_time and pam_group config files + (support for modern terminal devices). Fixed infinite loop problem + with '\\[^\n]' in these files. (Bug 116076 - agmorgan) +* avoid potential SIGPIPE when writing to helper binaries with (Bug + 123399 - agmorgan) +* replaced bogus logic in the pam_cracklib module for determining if + the replacement is too similar to the old password (Bug 115055 - + agmorgan) +* added accessconf= feature to pam_access - request from + Aldrin Martoq and Meelis Roos (Bugs 111927,117240 - agmorgan) +* fix for pam_limit module not dealing with all limits Adam J. Richter + (Bug 119554 - agmorgan) +* comment fix describing fail_delay callback in _pam_types.h (Bug + 112646 - agmorgan) +* "likeauth" fix for pam_unix and pam_pwdb which (Bug 113596 - agmorgan) +* fix for pam_unix (support.c) to avoid segfault with NULL password + (Bug 113238 - vorlon) +* fix to pam_unix_passwd: try repeatedly to get a lock on the password + file, instead of failing immediately (Bug 108845 - fix vorlon) +* fix to pam_shells: logged information was not formatted correctly + (extra comma) (Bug 111491 - fix vorlon) +* fix for C++ application support (Bug 111645 - fix agmorgan) +* fix for typo in pam_client.h (Bug 111648 - fix agmorgan) +* removal of -lpam from pam_mkhomedir Makefile (Bug 116380 - fix agmorgan) +* autoconf support [Task ID 15788, Bug ID 108297 - agmorgan with help!] + - bugfix for libpamc.h include file [Bug ID 117476 - agmorgan] + - bugfix for pam_filter.h inclusion [Bug ID 117474 - agmorgan] + +0.72: Mon Dec 13 22:41:11 PST 1999 + +* patches from Debian (Ben Collins): pam_ftp supports event driven + conversations now; pwdb_chkpwd cleanup; pam_warn static compile fix; + user_db compiler warnings removed; debian defs file; pam_mail can + now be used as a session module +* ndbm compilation option for user_db module (fix explained by Richard Khoo) +* pam_cracklib bug fix +* packaging fixes & build from scratch stuff (Konst Bulatnikov & Frodo + Looijaard) +* -ldl appended to the libpam.so compilation make rule. (Charles Seeger) +* Red Hat security patch for pam_pwdb forwarded by Debian! (Ben + Collins. Fix provided by Andrey as it caught the problem earlier in the + code.) +* heuristic to prevent leaking filedescriptors to an agent. [This needs + to be better supported perhaps by an additional libpamc API function?] +* pam_userdb segfault fix from (Ben Collins) +* PAM draft spec extras added at request of 'sen_ml' + +0.71: Sun Nov 7 20:21:19 PST 1999 + +* added -lc to linker pass for pam_nologin module (glibc is weird). +* various header changes to lower the number of warnings on glibc + systems (Dan Yefimov) +* merged a bunch of Debian fixes/patches/documentation (Ben Collins) + things touched: libpam (minor); doc/modules/pam_unix.sgml; pam_env + (plus docs); pam_mkhomedir (new module for new home directories on + the fly...); pam_motd (new module); pam_limits (adjust to match + docs); pam_issue (new module + doc) [Some of these were also + submitted by Thorsten Kukuk] +* small hack to lower the number of warnings that pam_client.h was + generating. +* debian and SuSE apparently can use the pam_ftp module, so + removed the obsolete comment about this from the docs. (Thorsten + Kukuk) + +0.70: Fri Oct 8 22:05:30 PDT 1999 + +* bug fix for parsing of value=action tokens in libpam/pam_misc.c was + segfaulting (Jan Rekorajski and independently Matthew Melvin) +* numerous fixes from Thorsten Kukuk (icluding much needed fixes for + bitrot in modules and some documentation) that got included in SuSE 6.2. +* reentrancy issues in pam_unix and pam_cracklib resolved (Jan Rekorajski) +* added hosts_equiv_rootok module option to pam_rhosts module (Tim Berger) +* added comment about 'expose_account' module argument to admin and + module writers' docs (request from Michael K Johnson). +* myriad of bug fixes for libpamc - library now built by default and + works with the biomouse fingerprint scanner agent/module + (distributed separately). + +0.69: Sun Aug 1 20:25:37 PDT 1999 + +* c++ header #ifdef'ing for pam_appl.h (Tuomo Pyhala) +* added pam_userdb module (Cristian Gafton) +* minor documentation changes +* added in revised pam_client library (libpamc). Not installed by + default yet, since the example agent/module combo is not very secure. +* glibc fixes (Thorsten Kukuk, Adam J. Richter) + +0.68: Sun Jul 4 23:04:13 PDT 1999 + +* completely new pam_unix module from Jan Rekorajski and Stephen Langasek +* Jan Rekorajski pam_mail - support for Maildir format mailboxes +* Jan Rekorajski pam_cracklib - support for old password comparison +* Jan Rekorajski bug fix for pam_pwdb setcred reusing auth retval +* Andrey's pam_tally patch (lstat -> fstat) +* Robert Milkowski's additional pam_tally patches to **change format of + /var/log/faillog** to one from shadow-utils, add new option "per_user" + for pam_tally module, failure time logging, support for fail_line + field, and support for fail_locktime field with new option + no_lock_time. +* pam_tally: clean up the tally application too. +* Marcin Korzonek added process priority settings to pam_limits (bonus + points for adding to documentation!) +* Andrey's pam_pwdb patch (cleanup + md5 endian fubar fix) +* more binary prompt preparations (make misc conv more compatible with spec) +* modified callback hook for fail delay to be more useful with event + driven applications (changed function prototype - suspect no one + will notice). Documented this in app developer guide. +* documentation for pam_access from Tim Berger +* syntax fixes for the documentation - a long time since I've built it :*( + added some more names to the CREDITS file. + +0.67: Sat Jun 19 14:01:24 PDT 1999 + +* [dropped libpam_client - libpamc will be in the next release and + conforms to the developing spec in doc/specs/draft-morgan-pam.raw. + Sorry if you are keeping a PAM tree in CVS. CVS is a pain for + directories, but this directory was actually not referenced by + anything so the disruption should be light.] +* updates to pam_tally from Tim +* multiple updates from Stephen Langasek to pam_unix +* pam_filter had some trouble compiling (bug report from Sridhar) +* pam_wheel now attempts to identify the wheel group for the local + system instead of blindly assuming it is gid=0. In the case that + there is no "wheel" group, we default to assuming gid=0 is what was + meant - former behavior. (courtesy of Sridhar) +* NIS+ changes to pam_unix module from Dmitry O Panov +* hopefully, a fix for redefinition of LOG_AUTHPRIV (bug report Luke + Kenneth Casson Leighton) +* fix for minor typo in pam_wheel documentation (Jacek Kopecky) +* slightly more explanation of the [x=y] pam.conf syntax in the sys + admin guide. + +0.66: Mon Dec 28 20:22:23 PST 1998 + +* Started using cvs to keep track of changes to Linux-PAM. This will + likely break some of the automated building stuff (RPMs etc..). +* security bug fix to pam_unix and pam_tally from Andrey. +* modules make file is now more automatic. It should be possible to + unpack an external module in the modules directory and have it automatically + added to the build process. Also added a modules/download-all script + that will make such downloading easier. I'm happy to receive patches to + this file, informing the distribution of places from which to enrich itself. +* removed pam_system_log stuff. Thought about it long and hard: a + bad idea. If libc cannot guarantee a thread safe syslog, it needs + to be fixed and compatibility with other PAM libraries was + unnecessarily strained. +* SAG documentation changes: Seth Chaiklin +* rhosts: problems with NIS lookup failures with the root-uid check. + As a work-around, I've partially eliminated the need for the lookup + by supplying two new arguments: no_uid_check, superuser=. + As a general rule this is more pluggable, since this module might be + used as an authentication scheme for a network service that does not + need root privilege... +* authenticate retval -> setcred for pam_pwdb (likeauth arg). +* pam_pwdb event driven support +* non openlog pam_listfile logging +* BUGFIX: close filedescriptor in pam_group and pam_time (Emmanuel Galanos) +* Chris Adams' mailhash change for pam_mail module +* fixed malloc failure check in pam_handlers.c (follow up to comment + by Brad M. Garcia). +* update to _pam_compat.h (Brad M. Garcia) +* support static modules in libpam again (Brad M. Garcia) +* libpam/pam_misc.c for egcs to grok the code (Brad M. Garcia) +* added a solaris-2.5.1 defs file (revived by Derrick J Brashear) +* pam_listfile logs failed attempts +* added a comment (Michael K Johnson pointed it out) about sgml2latex + having a new syntax. I'll make it the change real when I upgrade... +* a little more text to the RFC, spelling fix from William J Buffam. +* minor changes to pam_securetty to accommodate event driven support. + +0.65: Sun Apr 5 22:29:09 PDT 1998 + +* added event driven programming extensions to libpam + - added PAM_INCOMPLETE handling to libpam/pam_dispatch.c + - added PAM_CONV_AGAIN which is a new conversation response that + should be mapped to PAM_INCOMPLETE by the module. + - ensured that the pam_get_user() function can resume + - changes to pam_strerror to accommodate above return codes + - clean up _pam_former_state at pam_end() + - ensured that former state is correctly initialized + - added resumption tests to pam_authenticate(), pam_chauthtok() + - added PAM_FAIL_DELAY item for pausing on failure + +* improved _pam_macros.h so that macros can be used as single commands + (Andrey) + +* reimplemented logging to avoid bad interactions with libc. Added + new functions, pam_[,v]system_log() to libpam's API. A programmer + can check for this function's availablility by checking if + HAVE_PAM_SYSTEM_LOG is #defined. + +* removed the reduce conflict from pam_conv1 creation -- I can sleep + again now. :^] + +* made building of static and dynamic libpam separate. This is + towards making it possible to build both under Solaris (for Derrick) + +* made USE_CRACKLIB a condition in unix module (Luke Kenneth Casson Leighton) + +* automated (quiet) config installation (Andrey) + +0.64: Thu Feb 19 23:30:24 PST 1998 Andrew Morgan + +* miscellaneous patches for building under Solaris (Derrick J Brashear) + +* removed STATIC support from a number of module Makefiles. Notably, + these modules are those that use libpwdb and caused difficulties + satisfying the build process. (Please submit patches to fix this...;) + +* reomved the union for binary packet conversations from + (_pam_types.h). This is now completely implemented in libpam_client. + +* Andrey's patch for working environment variable handling in + sh_secret module. + +* made the libpam_misc conversation function a bit more flexible with + respect to binary conversations. + +* added top level define (DEBUG_REL) for compiling in the form of + a debugging release. I use this on a Red Hat 4.2 system with little + chance of crashing the system as a whole. (Andrey has another + implementation of this -- with a spec file to match..) + +0.63: Wed Jan 28 22:55:30 PST 1998 Andrew Morgan + +* added libpam_client "convention" library. This makes explicit the + use of PAM_BINARY_PROMPT. It is a first cut, so don't take it too + seriously yet. Comments/suggestions for improvements are very + welcome. Note, this library does not compile by default. It will + be enabled when it is judged stable. The library comes with two + module/agent pairs and can be used with ssh using a patch available + from my pre-release directory [where you got this file.] + +* backward compatibility patch for libpam/pam_handlers.c (PAM_IGNORE + was working with neither "requistie" nor "required") and a DEBUG'ing + compile time bug with pam_dispatch.c (Savochkin Andrey Vladimirovich) + +* minor Makefile change from (Savochkin Andrey Vladimirovich) + +* added pam_afsauth, pam_afspass, pam_restrict, and pam_syslog hooks + (Derrick J Brashear) + +* pam_access use of uname(2) problematic (security problem + highlighted by Olaf Kirch). + +* pam_listfile went a bit crazy reading group membersips (problem + highlighted by Olaf Kirch and patched independently by Cristian + Gafton and Savochkin Andrey Vladimirovich) + +* compatibility hooks for solaris and hpux (Derrick J Brashear) + +* 64 bit Linux/alpha bug fixed in pam_rhosts (Andrew D. Isaacson) + +0.62: Wed Jan 14 14:10:55 PST 1998 Andrew Morgan + +* Derrick J Brashear's patches: adds the HP stuff missed in the first + patch; adds SunOS support; adds support for the Solaris native ld + instead of requiring gnu ld. + +* last line of .rhosts file need not contain a newline. (Bug reported by + Thompson Freeman.) + +0.61: Thu Jan 8 22:57:44 PST 1998 Andrew Morgan + +* complete rewrite of the "control flag" logic. Formerly, we were + limited to four flags: requisite, required, sufficient, optional. + We can now use these keywords _and_ a great deal more besides. + The extra logic was inspired by Vipin Samar, a preliminary patch was + written by Andy Berkheimer, but I "had some ideas of my own" and + that's what I've actually included. The basic idea is to allow the + admin to custom build a control flag with a series of token=value + pairs inside square brackets. Eg., '[default=die success=ok]' which + is pretty close to a synonym for 'requisite'. I'll try to document it + better in the sys-admin guide but I'm pretty sure it is a change for + the better.... If what is in the sys-admin guide is not good enough + for you, just take a look at the source for libpam ;^) + +0.59: Thu Jan 8 22:27:22 PST 1998 Andrew Morgan + +* better handling of empty lines in .rhosts file. (Formerly, we asked + the nameserver about them!) Fix from Hugh Daschbach. + +* _broke_some_binary_compatibility_ with previous versions to become + compliant with X/Open's XSSO spec. Specifically, this has been + by changing the prototype for pam_strerror(). + +* altered the convention for the conversation mechanism to agree + with that of Sun. (number of responses 'now=' number of messages + with help from Cristian for finding a bug.. Cristian also found a + nasty speradic segfault bug -- Thanks!) + +* added NIS+ support to pam_unix_* + +* fixed a "regular file checking" problem with the ~/.rhosts sanity + check. Added "privategroup" option to permit group write permission + on the ~/.rhosts file in the case that the group owner has the same + name as the authenticating user. :*) "promiscuous" and "suppress" + were not usable! + +* added glibc compatibility to pam_rhosts_auth (protected __USE_MISC + with #ifndef since my libc already defines it!). + +* Security fix from Savochkin Andrey Vladimirovich with suggested + modification from Olaf Seibert. + +* preC contains mostly code clean-ups and a number of changes to + _pam_macros. + +0.58: whenever + +* pam_getenvlist() has a more robust definition (XSSO) than was previously + thought. It would seem that we no longer need pam_misc_copy_env() + which was there to provide the robustness that pam_getenvlist() + lacked before... + + Accordingly, I have REMOVED the prototype from libpam_misc. (The + function, however, will remain in the library as a wrapper for + legacy apps, but will likely be removed from libpam_misc-1.0.) PLEASE + FIX YOUR APPS *BEFORE* WE GET THERE! + +* Alexy Nogin reported garbage output from pam_env in the case of + a non-existent environment variable. + +* 'fixed' pwdb compilation for pam_wheel. Not very cleanly + done.. Mmmm. Should really clean up the entire source tree... + +* added prototypes for mapping functions + + <**WARNING**> + + various constants have had there names changed. Numerical values have + been retained but be aware some source old modules/applications will + need to be fixed before recompilation. + + + +* appended documentation to README for pam_rhosts module (Nicolai + Langfeldt). + +* verified X/Open compatibility of header files - note, where we differ + it is at the level of compilation warnings and the use of 'const char *' + instead of 'char *'. Previously, Sun(X/open) have revised their spec + to be more 'const'-ervative in the light of comments from Linux-PAM + development. + +* Ooops! PAM_AUTHTOKEN_REQD should have been PAM_NEW_AUTHTOK_REQD. + + changed: pam_pwdb(pam_unix_acct) (also bug fix for + _shadow_acct_mgmt_exp() return value), pam_stress, + libpam/pam_dispatch, blank, xsh. + +* New: PAM_AUTHTOK_EXPIRED - password has expired. + +* Ooops! PAM_CRED_ESTABLISH (etc.) should have been PAM_ESTABLISH_CRED + etc... (changed - this may break some people's modules - PLEASE TAKE + NOTE!) + changed: pam_group, pam_mail, blank, xsh; module and appl + docs, pam_setcred manual page. + +* renamed internal _pam_handle structure to be pam_handle as per XSSO. + +* added PAM_RADIO_TYPE (for multiple choice input method). Also + added PAM_BINARY_{MSG,PROMPT} (for interaction out of sight of user + - this could be used for RSA type authentication but is currently + just there for experimental purposes). The _BINARY_ types are now + usable with hooks in the libpam_misc conversation function. Still + have to add PAM_RADIO_TYPE. + +* added pam_access module (Alexei Nogin) + +* added documentation for pam_lastlog. Also modified the module to + not (by default) print "welcome to your new account" when it cannot + find a utmp entry for the user (you can turn this on with the + "never" argument). + +* small correction to the pam_fail_delay manual page. Either the appl or + the modules header file will prototype this function. + +* added "bigcrypt" (DEC's C2) algorithm(0) to pam_pwdb. (Andy Phillips) + +* *BSD tweaking for various #include's etc. (pam_lastlog, pam_rhosts, + pam_wheel, libpam/pam_handlers). (Michael Smith) + +* added configuration directory $SCONFIGED for module specific + configuration files. + +* added two new "linked" man pages (pam.conf(8) and pam.d(8)) + +* included a reasonable default for /etc/pam.conf (which can be + translated to /etc/pam.d/* files with the pam_conv1 binary) + +* fixed the names of the new configuration files in + conf/pam_conv1/pam_conv.y + +* fixed make check. + +* pam_lastlog fixed to handle UID in virgin part of /var/log/lastlog + (bug report from Ronald Wahl). + +* grammar fix in pam_cracklib + +* segfault avoided in pam_pwdb (getting user). Updating of passwords + that are directed to a "new" database are more robust now (bug noted + by Michael K. Johnson). Added "unix" module argument for migrating + passwords from another database to /etc/passwd. (documentation + updated). Removed "bad username []" warning for empty passwords - + on again if you supply the 'debug' module argument. + +* ctrl-D respected in conversation function (libpam_misc) + +* Removed -DPAM_FAIL_DELAY_ON from top-level Makefile. Nothing in + the distribution uses it. I guess this change happened a while + back, basically I'm trying to make the module parts of the + distribution "source compatible" with the RFC definition of PAM. + This implementation of PAM is a superset of that definition. I have + added the following symbols to the Linux-PAM header files: + + PAM_DATA_SILENT (see _pam_types.h) + HAVE_PAM_FAIL_DELAY (see _pam_types.h) + PAM_DATA_REPLACE (see _pam_modules.h) + + Any module (or application) that wants to utilize these features, + should check (#ifdef) for these tokens before using the associated + functionality. (Credit to Michael K. Johnson for pointing out my + earlier omission: not documenting this change :*) + +* first stab at making modules more independent of full library + source. Modules converted: + pam_deny + pam_permit + pam_lastlog + pam_pwdb + +* pam_env.c: #include added to ease GNU libc use. (Michael + K. Johnson) + +* pam_unix_passwd fixes to shadow aging code (Eliot Frank) + +* added README for pam_tally + +0.57: Fri Apr 4 23:00:45 PST 1997 Andrew Morgan + +* added "nodelay" argument to pam_pwdb. This can be used to turn off + the call to pam_fail_delay that takes effect when the user fails to + authenticate themself. + +* added "suppress" argument to pam_rhosts_auth module. This will stop + printing the "rlogin failure message" when the user does not have a + .rhosts file. + +* Extra fixes for FAKEROOT in Makefiles (Savochkin Andrey + Vladimirovich) + +* pam_tally added to tree courtesy of Tim Baverstock + +* pam_rhosts_auth was failing to read NFS mounted .rhosts + files. (Fixed by Peter Allgeyer). Refixed and further enhanced + (netgroups) by Nicolai Langfeldt. [Credit also to G.Wilford for some + changes that were not actually included..] + +* optional (#ifdef PAM_READ_BOTH_CONFS) support for parsing of pam.d/ + AND pam.conf files (Elliot Lee). + +* Added (and signed) Cristian's PGP key. (I've never met him, but I am + convinced the key belongs to the guy that is making the PAM rpms and + also producing libpwdb. Please note, I will not be signing anyone + else's key without a personal introduction..) + +* fixed erroneous syslog warning in pam_listfile (Savochkin Andrey + Vladimirovich, whole file reformatted by Cristian) + +* modified pam_securetty to return PAM_IGNORE in the case that the user's + name is not known to the system (was previously, PAM_USER_UNKNOWN). The + Rationale is that pam_securetty's sole purpose is to prevent superuser + login anywhere other than at the console. It is not its concern that the + user is unknown - only that they are _not_ root. Returning + PAM_IGNORE, however, insures that the pam_securetty can never be used to + "authenticate" a non-existent user. (Cristian Gafton with bug report from + Roger Hu) + +* Modified pam_nologin to display the no-login message when the user + is not known. The return value in this case is still PAM_USER_UNKNOWN. + (Bug report from Cristian Gafton) + +* Added NEED_LCKPWD for pam_unix/ This is used to define the locking + functions and should only be turned on if you don't have them in + your libc. + +* tidied up pam_lastlog and pam_pwdb: removed function that was never used. + +* Note for package maintainers: I have added $(FAKEROOT) to the list of + environment variables. This should help greatly when you build PAM + in a subdirectory. I've gone through the tree and tried to make + everything compatible with it. + +* added pam_env (courtesy of Dave Kinchlea) + +* removed pam_passwd+ from the tree. It has not been maintained in a + long time and running a shell script was basically insecure. I've + indicated where you can pick up the source if you want it. + +* #define HAVE_PAM_FAIL_DELAY . Applications can conditionally compile + with this if they want to see if the facility is available. It is + now always available. (corresponding compilation cleanups..) + +* _pam_sanitize() added to pam_misc. It purges the PAM_AUTHTOK and + PAM_OLDAUTHTOK items. (calls replaced in pam_auth and pam_password) + +* pam_rhosts now knows about the '+' entry. Since I think this is a + dangerous thing, I have required that the sysadmin supply the + "promiscuous" flag for it in the corresponding configuration file + before it will work. + +* FULL_LINUX_PAM_SOURCE_TREE exported from the top level make file. + If you want to build a module, you can test for this to determine if + it should take its directions from above or supply default locations + for installation. Etc. + +0.56: Sat Feb 15 12:21:01 PST 1997 + +* pam_handlers.c can now interpret the pam.d/ service config tree: + - if /etc/pam.d/ exists /etc/pam.conf is IGNORED + (otherwise /etc/pam.conf is treated as before) + - given /etc/pam.d/ + . config files are named (in lower case) by service-name + . config files have same syntax as /etc/pam.conf except + that the "service-name" field is not present. (there + are thus three manditory fields (and arguments are + optional): + + module-type control-flag module-path optional-args... + + ) + +* included conf/pam_conv1 for converting pam.conf to a pam.d/ version + 1.0 directory tree. This program reads a pam.conf file on the + standard input stream and creates ./pam.d/ (in the local directory) + and fills it with ./pam.d/"service-name" files. + + *> Note: It will fail if ./pam.d/ already exists. + + PLEASE REPORT ANY BUGS WITH THIS CONVERSION PROGRAM... It currently + cannot retain comments from the old conf file, so take care to do this + by hand. Also, please email me with the fix that makes the + shift/reduce conflict go away... + +* Added default module path to libpam for modules (see pam_handlers.c) + it makes use of Makfile defined symbol: DEFAULT_MODULE_PATH which is + inhereted from the defs/* variable $(SECUREDIR). Removed module + paths from the sample pam.conf file as they are no longer needed. + +* pam_pwdb can now verify read protected passwords when it is not run + by root. This is via a helper binary that is setuid root. + +* pam_permit now prompts for a username if it is not already determined + +* pam_rhosts now honors "debug" and no longer hardwire's "root" as the + superuser's name. + +* pam_securetty now honors the "debug" flag + +* trouble parsing extra spaces fixed in pam_time and pam_group + +* added Michael K. Johnson's PGP key to the pgp.keys.asc list + +* pam_end->env not being free()'d: fixed + +* manuals relocated to section 3 + +* fixed bug in pam_mail.c, and enhanced to recognize '~' as a prefix + to indicate the $HOME of the user (courtesy David + Kinchlea). *Changed* from a "session" module to an "auth" + module. It cannot be used to authenticate a user, but it can be used + in setting credentials. + +* fixed a stupid bug in pam_warn.. Only PAM_SERVICE was being read :*( + +* pam_radius rewritten to exclusively make use of libpwdb. (minor fix + to Makefile for cleaning up - AGM) + +* pam_limits extended to limit the total number of logins on a system + at any given time. + +* libpam and libpam_misc use $(MAJOR_REL) and $(MINOR_REL) to set their + version numbers [defined in top level makefile] + +* bugfix in sed command in defs/redhat.defs (AGM's fault) + +* The following was related to a possibility of buffer overruns in + the syslogging code: removed fixed length array from syslogging + function in the following modules [capitalized the log identifier + so the sysadmin can "know" these are fixed on the local system], + + pam_ftp, pam_stress, pam_rootok, pam_securetty, + pam_listfile, pam_shells, pam_warn, pam_lastlog + and + pam_unix_passwd (where it was definitely _not_ exploitable) + +0.55: Sat Jan 4 14:43:02 PST 1997, Andrew Morgan + +* added "requisite" control_flag to /etc/pam.conf syntax. [See + Sys. Admin. Guide for explanation] changes to pam_handlers.c + +* completely new handling of garbled pam.conf lines. The modus + operandi now is to assume that any errors in the line are minor. + Errors of this sort should *most definitely* lead to the module + failing, however, just ignoring the line (as was the case + previously) can lead to gaping security holes(! Not foreseen by the + RFC). The "motivation" for the RFC's comments about ignoring garbled + lines is present in spirit in the new code: basically a garbled line + is treated like an instance of the pam_deny.so module. + changes to pam_handlers.c and pam_dispatch.c . + +* patched libpam, to (a) call _pam_init_handlers from pam_start() and + (b) to log a text error if there are no modules defined for a given + service when a call to a module is requested. [pam_start() and + pam_dispatch() were changed]. + +* patched pam_securetty to deal with "/dev/" prefix on PAM_TTY item. + +* reorganized the modules/Makefile to include *ALL* modules. It is now + the responsibility of the modules themselves to test whether they can + be compiled locally or not. + +* modified pam_group to add to the getgroups() list rather than overwrite + it. [In the case of "HAVE_LIBPWDB" we use the pwdb_..() calls to + translate the group names.]. Module now pays attention to + PAM_CRED_.. flag(!) + +* identified and removed bugs in field reading code of pam_time and + (thus) pam_group. + +* Cristian's patches to pam_listfile module, corresponding change to + documentation. + +* I've discovered &ero; for sgml! + Added pam_time documentation to the admin guide. + +* added manual pages: pam.8, pam_start.2(=pam_end.2), + pam_authenticate.2, pam_setcred.2, pam_strerror.2, + pam_open_session.2(=pam_close_session.2) and pam_chauthtok.2 . + +* added new modules: + + - pam_mail (tells the user if they have any new mail + and sets their MAIL env variable) + - pam_lastlog (reports on the last time this user called + this module) + +* new module hooks provided. + +* added a timeout feature to the conversation function in + libpam_misc. Documented it in the application developers' guide. + +* fixed bug in pam_misc_paste_env() function.. + +* slight modifications to wheel and rhosts writeup. + +* more security issues added to module and application guides. + +-- +Things present but not mentioned in previous release (sorry) + +* pam_pwdb module now resets the "last_change" entry before updating a + password. +-- + +Sat Nov 30 19:30:20 PST 1996, Andrew Morgan + +* added environment handling to libpam. involved change to _pam_types.h + also added supplementary functions to libpam_misc + +* added pam_radius - Cristian + +* slight speed up for pam_rhosts + +* significantly enhanced sys-admin documentation (8 p -> 41 p in + PostScript). Added to other documentation too. Mostly the changes + in the other docs concern the new PAM-environment support, there is + also some coverage of libpam_misc in the App. Developers' guide. + +* Cristian's patches to pam_limits and pam_pwdb. Fixing bugs. (MORE added) + +* adopted Cristian's _pam_macros.h file to help with common macros and + debugging stuff, gone through tree tidying up debugging lines to use + this [not complete]. + + - for consistency replaced DROP() with _pam_drop() + +* commented memory debugging in top level makefile + +* added the following modules + + - pam_warn log information to syslog(3) about service application + - pam_ftp if user is 'ftp' then set PAM_RUSER/PAM_RHOST with password + (comment about nologin added to last release's notes) + +* modified the pam_listfile module. It now declares a meaningful static + structure name. + +Sun Nov 10 13:26:39 PST 1996, Andrew Morgan + + **PLEASE *RE*AMEND YOUR PERSONAL LINKS** + + -------> http://parc.power.net/morgan/Linux-PAM/index.html <------- + + **PLEASE *RE*AMEND YOUR PERSONAL LINKS** + +A brief summary of what has changed: + +* many modules have been modified to accomodate fixing the pam_get_user() + change. Please take note if you have a module in this distribution. + +* pam_unix is now the pam_unix that Red Hat has been using and which + should be fairly well debugged. + + - I've added some #ifdef's to make it compile for me, and also + updated it with respect to the libpam-0.53, so have a look at the + .../modules/pam_unix/Makefile to enable cracklib and shadow features + + ** BECAUSE OF THIS, I cannot guarantee this code works as it ** + ** did for Red Hat. Please test and report any problems. ** + +* the pam_unix of .52 (renamed to pam_pwdb) has been enhanced and made + more flexible with by implementing it with respect to the new + "Password Database Library" see + + http://parc.power.net/morgan/libpwdb/index.html + + modules included in this release that require this library to + function are the following: + + - pam_pwdb (ne pam_unix-0.52 + some enhancements) + - pam_wheel + - pam_limits + - pam_nologin + +* Added some optional code for memory debugging. In order to support + this you have to enable MEMORY_DEBUG in the top level makefile and + also #define MEMORY_DEBUG in your applications when they are compiled. + The extra code resides in libpam (compiled if MEMORY_DEBUG is defined) + and the macros for malloc etc. are to be found at the end of + _pam_types.h + +* used above code to locate two memory leaks in pam_unix module and two + in libpam (pam_handlers.h) + +* pam_get_user() now sets the PAM_USER item. After reading the Sun + manual page again, it was clear that it should do this. Various + modules have been assuming this and now I have modified most of them + to account for this change. Additionally, pam_get_user() is now + located in the module include file; modules are supposed to be the + ones that use it(!) [Note, this is explicitly contrary to the Sun + manual page, but in the spirit of the Linux distribution to date.] + +* replaced -D"LINUX" with -D"LINUX_PAM" as this is more explicit and less + likely to be confused with -D"linux". + Also, modified the libpam #include files to behave more like the Sun + ones #ifndef LINUX_PAM. + +* removed + +0. Before I begin, Linux-PAM has a new primary distribution site (kindly +donated by Power Net Inc., Los Angeles) + + **PLEASE AMMEND YOUR PERSONAL LINKS** + + -------> http://www.power.net/morgan/Linux-PAM <------- + + **PLEASE AMMEND YOUR PERSONAL LINKS** + +1. I'm hoping to make the next release a bug-fix release... So please find + all the bugs(! ;^) + +2. here are the changes for .52: + +* minor changes to module documentation [Incidently, it is now + available on-line from the WWW page above]. More changes to follow in + the next two releases. PLEASE EMAIL me or the list if there is + anything that isn't clear! + +* completely changed the unix module. Now a single module for all four + management groups (this meant that I could define all functions as + static that were not part of the pam_sm_... scheme. AGM) + + - Shadow support added +PASSWD - Elliot's account management included, and enhanced by Cristian Gafton. + - MD5 password support added by Cristian Gafton. + - maxtries for authentication now enforced. + - Password changing function in pam_unix now works! + Although obviously, I'm not going to *guarantee* it ;^) . + - stole Marek's locking code from the Red Hat unix module. + [ If you like you can #ifdef it in or out ... ] + + You can configure the module more from its Makefile in + 0.52/modules/pam_unix/ + + If you are nervous that it will destroy your /etc/passwd or shadow + files then EDIT the 0.52/modules/pam_unix/pam_unix_pass.-c file. + Here is the warning comment from this file... + +-------------8<----------------- +/* + * + * Uncomment the following #define if you are paranoid, and do not + * want to risk losing your /etc/passwd or shadow files. + * It works for me (AGM) but there are no guarantees. + * + * + */ +/* #define TMP__FILE */ +------------->8----------------- + + *** If anyone has any trouble, please *say*. Your problem will be + fixed in the next release. Also please feel free to scour the + code for race conditions etc... + +[* The above change requires that you purge your /usr/lib/security + directory of the old pam_unix_XXX.so modules: they will NOT be deleted + with a 'make remove'.] + +* the prototype for the cleanup function supplied to pam_set_data used + to return "int". According to Sun it should be "void". CHANGED. + +* added some definitions for the 'error_status' mask values that are + passed to the cleanup function associated with each + module-data-item. These numbers were needed to keep up with changing + a data item (see for example the code in pam_unix/support.-c that + manages the maximum number of retries so far). Will see what Sun says + (current indications are positive); this may be undone before 1.0 is + released. Here are the definitions (from pam_modules.h). + +#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */ +#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */ + +* Changed the .../conf/pam.conf file. It now points to the new + pam_unix module for 'su' and 'passwd' [can get these as SimpleApps -- + I use them for testing. A more extensive selection of applications is + available from Red Hat...] + +* corrected a bug in pam_dispatch. Basically, the problem was that if + all the modules were "sufficient" then the return value for this + function was never set. The net effect was that _pam_dispatch_aux + returned success when all the sufficient modules failed. :^( I think + this is the correct fix to a problem that the Red Hat folks had + found... + +sopwith* Removed advisory locking from libpam (thanks for the POSIX patch + goes to Josh Wilmes's, my apologies for not using it in the + end.). Advisory locking did not seem sufficiently secure for libpam. + Thanks to Werner Almesberger for identifying the corresponding "denial + of service attack". :*( + +* related to fix, have introduced a lock file /var/lock/subsys/PAM + that can be used to indicate the system should pay attention to + advisory locking on /etc/pam.conf file. To implement this you need to + define PAM_LOCKING though. (see .52/libpam) + +* modified pam_fail_delay() function. Couldn't find the "not working" + problem indicated by Michael, but modified it to do pseudo-random + delays based on the values indicated by pam_fail_delay() -- the + function "that may eventually go away"... Although Sun is warming to + the idea. + +* new modules include: + + pam_shells - authentication for users with a shell listed in + /etc/shells. Erik Troan + + pam_listfile - authentication based on the contents of files. + Set to be more general than the above in the + future. UNTESTED. Elliot Lee <@redhat.com> + [Note, this module compiles with a non-trivial + warning: AGM] + +Thu Aug 8 22:32:15 PDT 1996 (Andrew Morgan ) + +* modified makefiles to take more of their installation instructions + from the top level makefile. Desired for integration into the Debian + distribution, and generally a good idea. + +* fixed memory arithmetic in pam_handlers + -- still need to track down why failure to load modules can lead to + authentication succeding.. + +* added tags for new modules (smartcards from Alex -- just a promise + at this stage) and a new module from Elliot Lee; pam_securetty + +* I have not had time to smooth out the wrinkles with it, but Alex's + pam_unix modifications are provided in pam_unix-alex (in the modules + directory) they will not be compiled by 'make all' and I can't even + say if they do compile... I will try to look at them for .52 but, in + the mean time please feel free to study/fix/discuss what is there. + +* pam_rhosts module. Removed code for manually setting the ruser + etc. This was not very secure. + +* [remade .ps docs to be in letter format -- my printer complains + about a4] + +Sunday July, 7 12:45:00 PST 1996 (Andrew Morgan ) + +* No longer accompanying the Linux-PAM release with apps installed. + [Will provide what was here in a separate package.. (soon) +lib Also see http://www.redhat.com/pam for some more (in .rpm form...)] + +* renamed libmisc to libpam_misc. It is currently configured to only compile + the static library. For some strange reason (perhaps someone can + investigate) my Linux 2.0.0 kernel with RedHat 3.0.3 system + segfaults when I compile it to be a dynamic library. The segfault + seems to be inside the call to the ** dl_XXX ** function...!? + + There is a simple flag in the libpam_misc/Makefile to turn on dynamic + compiles. + +* Added a little unofficial code for delay support in libpam (will probably + disappear later..) There is some documentation for it in the pam_modules + doc now. That will obviously go too. + +* rewritten pam_time to use *logic* to specify the stringing together of + users/times/terminals etc.. (what was there before was superficially + logical but basically un-predictable!) + +* added pam_group. Its syntax is almost identical to pam_time but it + has another field added; a list of groups to make the user a member + of if they pass the previous tests. It seems to not co-exist too well + with the groups in the /etc/group but I hope to have that fixed by + the next release... + +* minor re-formatting of pam_modules documentation + +* removed ...// since it wasn't being used and didn't look like it + would be! + +GCCSunday 23 22:35:00 PST 1996 (Andrew Morgan ) + +* The major change is the addition of a new module: pam_time for + restricting access on terminals at given times for indicated users + it comes with its own configuration file /etc/security/time.conf + and the sample file simply restricts 'you' from satisfying the blank + application if they try to use blank from any tty* + +* Small changes include +- altered pam.conf to demonstrate above new module (try typing username: you) +- very minor changes to the docs (pam_appl and pam_modules) + +Saturday June 2 01:40:00 PST 1996 (Andrew Morgan ) + +*** PLEASE READ THE README, it has changed *** + +* NOTE, 'su' exhibits a "system error", when static linking is + used. This is because the pam_unix_... module currently only has + partial static linking support. This is likely to change on Monday + June 3, when Alex makes his latest version availible. I will include + the updated module in next release. + +changes for .42: + +* modified the way in which libpam/pam_modules.h defines prototypes for + the pam_sm_ functions. Now the module must declare which functions it + is to provide *before* the #include line. + (for contrasting examples, see the pam_deny and pam_rootok modules) + This removed the ugly hack of defining functions that are never called + to overcome warnings... This seems much tidier. +insterted* updated the TODO list. (changed mailing list address) +* updated README in .../modules to reflect modifications to static + compliation protocol +* modified the pam_modules documentation to describe this. +* corrected last argument of pam_get_item( ... ) in + pam_appl/modules.sgml, to "const void **". +* altered GNU GPL's in the documentation, and various other parts of + the distribution. *Please check* that any code you are responsible for + is corrected. +* Added ./Copyright (please check that it is acceptable) +* updated ./README to make current and indicate the new mailing list + address +* have completely rewritten pam_filter. It now runs modular filter + executables (stored in /usr/sbin/pam_filter/) This should make it + trivial for others to write their own filters.. If you want yours + included in the distribution please email the list/me. +* changes to libpam; there was a silly bug with multiple arguments on a + pam.conf line that was broken with a '\'. +* 'su' rearranged code (to make better use of PAM) + *Also* now uses POSIX signals--this should help the Alpha port. +* 'passwd' now uses getlogin() to determine who's passwords to change. + +Sunday May 26 9:00:00 PST 1996 (Andrew Morgan ) + +* fixed module makefiles to create needed dynamic/static subdirectories + +Saturday May 25 20:30:27.8 PST 1996 (Andrew Morgan ) + +* LOTS has changed regarding how the modules/libpam are built. +* Michael's mostly complete changes for static support--see below + (Andrew got a little carried away and automated the static linking + of modules---bugs are likely mine ;( ) +* Thanks mostly to Michael, libpam now compiles without a single warning :^] +* made static modules/library optional. +CFLAGS* added 'make sterile' to top level makefile. This does extraclean and remove +* added Michael and Joseph to documentation credits (and a subsection for + future documentation of static module support in pam_modules.sgml) +* libpam; many changes to makefiles and also automated the inclusion of + static module objects in pam_static.c +* modified modules for automated static/dynamic support. Added static & + dynamic subdirectories, as instructed by Michael +* removed an annoying syslog message from pam_filter: "parent exited.." +* updated todo list (anyone know anything about svgalib/X? we probably should + have some support for these...) + +Friday May 24 16:30:15 EDT 1996 (Michael K. Johnson ) + +* Added first (incomplete) cut at static support. + This includes: + . changes in libpam, including a new file, pam_static.c + . changes to modules including exporting struct of function pointers + . static and dynamic linking can be combined + . right now, the only working combinations are just dynamic + linking and dynamic libpam.so with static modules linked + into libpam.so. That's on the list of things to fix... + . modules are built differently depending on whether they + are static or dynamic. Therefore, there are two directories + under each module directory, one for static, and one for + dynamic modules. +* Fixed random brokenness in the Makefiles. [ foo -nt bar ] is + rather redundant in a makefile, for instance. Also, passing + on the command line is broken because it cannot be + overridden in any way (even adding important parts) in lower-level + makefiles. +* Unfortunately, fixing some of the brokenness meant that I used + GNU-specific stuff. However, I *think* that there was GNU-specific + stuff already. And I think that we should just use the GNU + extensions, because any platform that GNU make doesn't port to + easily will be hard to port to anyway. It also won't be likely +passwd to handle autoconf, which was Ted's suggestion for getting + around limitations in standard make... + For now, I suggest that we just use some simple GNU-specific + extensions. + +Monday May 20 22:00:00 PST 1996 (Andrew Morgan ) + +* added some text to pam_modules.sgml +* corrected Marek's name in all documentation +* made pam_stress conform to chauthtok conventions -- ie can now request + old password before proceeding. +* included Alex's latest unix module +* included Al's + password strength checking module +* included pam_rootok module +* fixed too many bugs in libpam.. all subtly related to the argument lists + or use of syslog. Added more debugging lines here too. +* fixed the pam.conf file +* deleted pam_test module. It is pretty old and basically superceeded + by pam_stress + +Friday May 9 1:00:00 PST 1996 (Andrew Morgan ) + +* updated documentaion, added Al Longyear to credits and corrected the + spelling of Jeff's name(!). Most changes to pam.sgml (even added a figure!) +* new module pam_rhosts_auth (from Al Longyear) +* new apps rlogind and ftpd (a patch) from Al. +* modified 'passwd' to not call pam_authenticate (note, none of the + modules respect this convention yet!) +* fixed bug in libpam that caused trouble if the last line of a + pam.conf file ends with a module name and no newline character +* also made more compatable with documentation, in that bad lines in + pam.conf are now ignored rather than causing libpam to return an + error to the app. +* libpam now overwrites the AUTHTOKs when returning from + pam_authenticate and pam_chauthtok calls (as per Sun/RFC too) +* libpam is now installed as libpam.so.XXX in a way that ldconfig can + handle! + + +Wednesday May 1 22:00:00 PST 1996 (Andrew Morgan ) + +* removed .../test directory, use .../examples from now on. +* added .../apps directory for fully functional applications + - the apps directory contains directories that actually contain the apps. + the idea is to make application compilation conditional on the presence + of the directory. Note, there are entries in the Makefile for + 'login' and 'ftpd' that are ready for installation... Email me if + you want to reserve a directory name for an application you are + working on... +* similar changes to .../modules makefile [entries for pam_skey and + pam_kerberos created---awaiting the directories.] Email me if you + want to register another module... +* minor changes to docs.. Not really worth reprinting them quite yet! + [save the trees] +* added misc_conv to libmisc. it is a generic conversation function + for text based applications. [would be nice to see someone create + an Xlib and/or svgalib version] +* fixed ctrl-z/c bug with pam_filter module [try xsh with the default + pam.conf file] +* added 'required' argument to 'pam_stress' module. +* added a TODO list... other suggestions to the list please. + +Saturday April 7 00:00:00 PST 1996 ( Andrew Morgan ) + +* Alex and Marek please note I have altered _pam_auth_unix a little, to + make it get the passwords with the "proper method" (and also fixed it + to not have as many compiler warnings) +* updated the conf/pam.conf file +* added new example application examples/xsh.c (like blank but invokes + /bin/sh) +* Marc's patches for examples/blank.c (and AGM's too) +* fixed stacking of modules in libpam/pam_handlers.c +* fixed RESETing in libpam/pam_item.c +* added new module modules/pam_filter/ to demonstrate the possibility + of inserting an arbitrary filter between the terminal and the + application that could do customized logging etc... (see use of + bin/xsh as defined in conf/pam.conf) + + +Saturday March 16 19:00:00 PST 1996 ( Andrew Morgan ) + +These notes are for 0.3 I don't think I've left anything important +out, but I will use emacs 'C-x v a' next time! (Thanks Jeff) + + * not much has changed with the functionality of the Linux-PAM lib + .../libpam + - pam_password calls module twice with different arguments + - added const to some of the function arguments + - added PAM_MAX_MES_ to + - was a lot over zealous about purging old passwords... + I have removed much of this from source to make it + more compatible with SUN. + - moved some PAM_... tokens to pam_modules.h from _pam_types.h + (no-one should notice) + + * added three modules: pam_permit pam_deny pam_stress + no prizes for guessing what the first two do. The third is + a reasonably complete (functional) module. Is intended for testing + applications with. + + * fixed a few pieces of examples/blank.c so that it works (with + pam_stress) + + * ammended the documentation. Looking better, but suggestions/comments + very welcome! + +Sunday March 10 10:50:00 PST 1996 ( Andrew Morgan ) + +These notes are for Linux-PAM release 0.21. They cover what's changed +since I relased 0.2. + + * am now using RCS + * substantially changed ./README + * fixed bug reading \\\n in pam.conf file + * small changes to documentation + * added `blank' application to ./examples (could be viewed as + a `Linux-PAM aware' application template.) + * oops. now including pam_passwd.o and pam_session.o in pamlib.so + * compute md5 checksums for all the source when making a release + - added `make check' and `make RCScheck' to compute md5 checksums + * create a second tar file with all the RCS files in. + * removed the .html and .txt docs, supplying sgml sources instead. + - see README for info on where to get .ps files + +Thursday March 6 0:44:?? PST 1996 ( Andrew Morgan ) + +These notes are for Linux-PAM release 0.2. They cover what's changed +since Marc Ewing relased 0.1. + +**** Please note. All of the directories in this release have been modified +**** slightly to conform to the new pamlib. A couple of new directories have +**** been added. As well as some documentation. If some of your code +**** was in the previous release. Feel free to update it, but please +**** try to conform to the new headers and Makefiles. + +* Andrew Morgan (morgan@physics.ucla.edu) is making this release + availible, Marc has been busy...! + +* Marc's pam-0.1/lib has been (quietly) enhanced and integrated into + Alex Yurie's collected tree of library and module code + (linux-pam.prop.1.tar.gz). Most of the changes are to do with error + checking. Some more robustness in the reading of the pam.conf file + and the addition of the pam_get_user() function. + +* The pam_*.h files have been reorganized to logically enforce the + separation of modules from applications. [Don't panic! Apart from + changing references of the form + + #include "pam_appl.h" + + to + + #include + + The reorganization should be backwardly compatable (ie. a module + written for SUN will be as compatable as it was before with the + previous version ;)~ ] + + (All of the source in this tree now conforms to this scheme...) + + The new reorganization means that modules can be compiled with a + single header, , and applications with + . + +* I have tried to remove all the compiler warnings from the updated + "pamlib/*.c" files. On my system, (with a slightly modified + email me if it interests you..) there are only two warnings that + remain: they are that ansi does not permit void --> fn ptr + assignment. K&Rv2 doesn't mention this....? As a matter of principle, + if anyone knows how to get rid of that warning... please + tell. Thanks! "-pedantic" + +* you can "make all" as a plain user, but + +* to "make install" you must be root. The include files are placed in + /usr/include/security. The libpam.so library is installed in /usr/lib + and the modules in /usr/lib/security. The two test binaries + are installed in the Linux-PAM-0.2/bin directory and a chance is given to + replace your /etc/pam.conf file with the one in Linux-PAM-0.2/conf. + +* I have included some documentation (pretty preliminary at the +moment) which I have been working on in .../doc . + +I have had a little trouble with the modules, but atleast there are no +segfaults! Please try it out and discuss your results... I actually +hope it all works for you. But, Email any bugs/suggestions to the +Linux-PAM list: linux-pam@mit.edu ..... + +Regards, + +Andrew Morgan +(morgan@physics.ucla.edu) + + +Sat Feb 17 17:30:24 EST 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu) + + * conf directory created with example of pam_conf + * stable code from pam_unix is added to modules/pam_unix + * test/test.c now requests username and password and attempts + to perform authentication + diff --git a/Linux-PAM/Copyright b/Linux-PAM/Copyright new file mode 100644 index 00000000..2f27a2ee --- /dev/null +++ b/Linux-PAM/Copyright @@ -0,0 +1,41 @@ +Unless otherwise *explicitly* stated the following text describes the +licensed conditions under which the contents of this Linux-PAM release +may be distributed: + +------------------------------------------------------------------------- +Redistribution and use in source and binary forms of Linux-PAM, with +or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License, in which case the provisions of the GNU +GPL are required INSTEAD OF the above restrictions. (This clause is +necessary due to a potential conflict between the GNU GPL and the +restrictions contained in a BSD-style copyright.) + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +------------------------------------------------------------------------- + diff --git a/Linux-PAM/Make.Rules.in b/Linux-PAM/Make.Rules.in new file mode 100644 index 00000000..cb537d16 --- /dev/null +++ b/Linux-PAM/Make.Rules.in @@ -0,0 +1,110 @@ +## +## $Id: Make.Rules.in,v 1.1.1.2 2002/09/15 20:08:19 hartmans Exp $ +## +## @configure_input@ +## + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +includedir = @includedir@ + +absolute_srcdir = @LOCALSRCDIR@ +absolute_objdir = @LOCALOBJDIR@ + +# major and minor numbers of this release +MAJOR_REL=@LIBPAM_VERSION_MAJOR@ +MINOR_REL=@LIBPAM_VERSION_MINOR@ + +# The following is the generic set of compiler options for compiling +# Linux-PAM. True, they are a little anal. Pay attention to the comments +# they generate. + +HEADER_DIRS=-I./include -I$(absolute_srcdir)/libpam/include \ + -I$(absolute_objdir) -I$(absolute_srcdir)/libpamc/include +WARNINGS=@WARNINGS@ +OS_CFLAGS=@OS_CFLAGS@ +PIC=@PIC@ + +# Mode to install shared libraries with +SHLIBMODE=@SHLIBMODE@ + +NEED_LINK_LIB_C=@PAM_NEEDS_LIBC@ +HAVE_LCKPWDF=@HAVE_LCKPWDF@ +HAVE_LIBCRACK=@HAVE_LIBCRACK@ +HAVE_LIBCRYPT=@HAVE_LIBCRYPT@ +HAVE_LIBUTIL=@HAVE_LIBUTIL@ +HAVE_NDBM_H=@HAVE_NDBM_H@ +HAVE_LIBNDBM=@HAVE_LIBNDBM@ +HAVE_LIBDB=@HAVE_LIBDB@ +HAVE_LIBFL=@HAVE_LIBFL@ +HAVE_LIBNSL=@HAVE_LIBNSL@ +HAVE_LIBPWDB=@HAVE_LIBPWDB@ + +ifeq (@HAVE_LIBFLEX@,yes) +LINK_LIBLEX=-lfl +else +ifeq (@HAVE_LIBLEX@,yes) +LINK_LIBLEX=-ll +endif +endif + +# documentation support +HAVE_SGML2TXT=@HAVE_SGML2TXT@ +HAVE_SGML2HTML=@HAVE_SGML2HTML@ +HAVE_PS2PDF=@HAVE_PS2PDF@ +PSER=@PSER@ +DOCDIR=@DOCDIR@ +MANDIR=@MANDIR@ + +# configuration settings +WITH_DEBUG=@WITH_DEBUG@ +WITH_MEMORY_DEBUG=@WITH_MEMORY_DEBUG@ +WITH_LIBDEBUG=@WITH_LIBDEBUG@ +WITH_PAMLOCKING=@WITH_PAMLOCKING@ +WITH_LCKPWDF=@WITH_LCKPWDF@ +STATIC_LIBPAM=@STATIC_LIBPAM@ +DYNAMIC_LIBPAM=@DYNAMIC_LIBPAM@ +STATIC=@STATIC@ +DYNAMIC=@DYNAMIC@ + +# Location of libraries when installed on the system +FAKEROOT=@FAKEROOT@ +SECUREDIR=@SECUREDIR@ +SCONFIGD=@SCONFIGDIR@ +SUPLEMENTED=@SUPLEMENTED@ +INCLUDED=@INCLUDEDIR@/security +CRACKLIB_DICTPATH=@CRACKLIB_DICTPATH@ + +# generic build setup +OS=@OS@ +CC=@CC@ +CFLAGS=$(WARNINGS) -D$(OS) $(OS_CFLAGS) $(HEADER_DIRS) @CONF_CFLAGS@ +LD=@LD@ +LD_D=@LD_D@ +LD_L=@LD_L@ +LDCONFIG=@LDCONFIG@ +DYNTYPE=@DYNTYPE@ +USESONAME=@USESONAME@ +NEEDSONAME=@NEEDSONAME@ +SOSWITCH=@SOSWITCH@ +LIBDL=@LIBDL@ +MKDIR=@MKDIR@ +INSTALL=@INSTALL@ +RANLIB=@RANLIB@ +STRIP=@STRIP@ +CC_STATIC=@CC_STATIC@ + +LINKLIBS = $(NEED_LINK_LIB_C) $(LIBDL) diff --git a/Linux-PAM/Makefile b/Linux-PAM/Makefile new file mode 100644 index 00000000..cdc8505a --- /dev/null +++ b/Linux-PAM/Makefile @@ -0,0 +1,78 @@ +## +## $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:19 hartmans Exp $ +## + +## Note, ideally I would prefer it if this top level makefile did +## not get created by autoconf. As I find typing 'make' and relying +## on it to take care of all dependencies much more friendly than +## the multi-stage autoconf+make and also worry about updates to +## configure.in not getting propagated down the tree. (AGM) [I realise +## that this may not prove possible, but at least I tried.. Sigh.] + +DISTNAME=Linux-PAM + +ifeq ($(shell test \! -f Make.Rules || echo yes),yes) + include Make.Rules +endif + +THINGSTOMAKE = modules libpam libpamc libpam_misc doc examples + +all: $(THINGSTOMAKE) + +prep: + rm -f security + ln -sf . security + +clean: + if [ ! -f Make.Rules ]; then touch Make.Rules ; fi + for i in $(THINGSTOMAKE) ; do $(MAKE) -C $$i clean ; done + rm -f security *~ *.orig *.rej Make.Rules #*# + +distclean: clean + rm -f Make.Rules _pam_aconf.h + rm -f config.status config.cache config.log core + +maintainer-clean: distclean + @echo files should be ok for packaging now. + +# NB _pam_aconf.h.in changes will remake this too +Make.Rules: configure Make.Rules.in _pam_aconf.h.in + @echo XXX - not sure how to preserve past configure options.. + @echo XXX - so not attempting to. Feel free to run ./configure + @echo XXX - by hand, with the options you want. + ./configure + +_pam_aconf.h: Make.Rules + +configure: configure.in + @echo + @echo You do not appear to have an up-to-date ./configure file. + @echo Please run autoconf, and then ./configure [..options..] + @echo + @rm -f configure + @exit 1 + +$(THINGSTOMAKE): _pam_aconf.h prep + $(MAKE) -C $@ all + +install: _pam_aconf.h prep + $(MKDIR) $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 444 security/_pam_aconf.h $(FAKEROOT)$(INCLUDED) + for x in $(THINGSTOMAKE) ; do $(MAKE) -C $$x install ; done + +remove: + rm -f $(FAKEROOT)$(INCLUDED)/_pam_aconf.h + for x in $(THINGSTOMAKE) ; do $(MAKE) -C $$x remove ; done + +release: + @if [ ! -f Make.Rules ]; then echo $(MAKE) Make.Rules first ;exit 1 ;fi + @if [ ! -L ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ]; then \ + echo generating ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) link ; \ + ln -sf $(DISTNAME) ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ; \ + echo to ../$(DISTNAME) . ; fi + @diff ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/Make.Rules Make.Rules + $(MAKE) distclean + cd .. ; tar zvfc $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL).tar.gz \ + --exclude CVS --exclude .cvsignore --exclude '.#*' \ + $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/* + diff --git a/Linux-PAM/README b/Linux-PAM/README new file mode 100644 index 00000000..8aab912a --- /dev/null +++ b/Linux-PAM/README @@ -0,0 +1,28 @@ +# +# $Id: README,v 1.1.1.1 2001/04/29 04:16:21 hartmans Exp $ +# + +Hello! + +Thanks for downloading Linux-PAM. + +NOTES: + +How to use it is as follows: + + ./configure --help | less + ./configure + make + +Note, if you are worried - don't even think about doing the next line +(most Linux distributions already support PAM out of the box, so if +something goes wrong with installing the code from this version your +box may stop working..) + + make install + +That said, please report problems to me. + +Andrew Morgan + + diff --git a/Linux-PAM/_pam_aconf.h.in b/Linux-PAM/_pam_aconf.h.in new file mode 100644 index 00000000..14c6f9fd --- /dev/null +++ b/Linux-PAM/_pam_aconf.h.in @@ -0,0 +1,99 @@ +/* + * $Id: _pam_aconf.h.in,v 1.1.1.2 2002/09/15 20:08:20 hartmans Exp $ + * + * + */ + +#ifndef PAM_ACONF_H +#define PAM_ACONF_H + +/* lots of stuff gets written to /tmp/pam-debug.log */ +#undef DEBUG + +/* build libraries with different names (suffixed with 'd') */ +#undef WITH_LIBDEBUG + +/* provide a global locking facility within libpam */ +#undef PAM_LOCKING + +/* GNU systems as a class, all have the feature.h file */ +#undef HAVE_FEATURES_H +#ifdef HAVE_FEATURES_H +# define _SVID_SOURCE +# define _BSD_SOURCE +# define __USE_BSD +# define __USE_SVID +# define __USE_MISC +# define _GNU_SOURCE +# include +#endif /* HAVE_FEATURES_H */ + +/* we have libcrack available */ +#undef HAVE_LIBCRACK + +/* we have libcrypt - its not part of libc (do we need both definitions?) */ +#undef HAVE_LIBCRYPT +#undef HAVE_CRYPT_H + +/* we have libndbm and/or libdb */ +#undef HAVE_DB_H +#undef HAVE_NDBM_H + +/* have libfl (Flex) */ +#undef HAVE_LIBFL + +/* have libnsl - instead of libc support */ +#undef HAVE_LIBNSL + +/* have libpwdb - don't expect this to be important for much longer */ +#undef HAVE_LIBPWDB + +/* have gethostname() declared */ +#undef HAVE_GETHOSTNAME + +#undef HAVE_GETTIMEOFDAY +#undef HAVE_MKDIR +#undef HAVE_SELECT +#undef HAVE_STRCSPN +#undef HAVE_STRDUP +#undef HAVE_STRERROR +#undef HAVE_STRSPN +#undef HAVE_STRSTR +#undef HAVE_STRTOL +#undef HAVE_UNAME + +/* Define if reentrant declarations of standard nss functions are available */ +#undef HAVE_GETPWNAM_R +#undef HAVE_GETGRNAM_R + +/* ugly hack to partially support old pam_strerror syntax */ +#undef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT + +/* read both confs - read /etc/pam.d and /etc/pam.conf in serial */ +#undef PAM_READ_BOTH_CONFS + +#undef HAVE_PATHS_H +#ifdef HAVE_PATHS_H +#include +#endif +/* location of the mail spool directory */ +#undef PAM_PATH_MAILDIR + +/* where should we include setfsuid's prototype from? If this is not + defined, we get it from unistd.h */ +#undef HAVE_SYS_FSUID_H + +/* track all memory allocations and liberations */ +#undef MEMORY_DEBUG +#ifdef MEMORY_DEBUG +/* + * this is basically a hack - we need to include a semiarbitrary + * number of headers to ensure that we don't get silly prototype/macro + * confusion. + */ +# include +# include +# include +#endif /* MEMORY_DEBUG */ + +#endif /* PAM_ACONF_H */ diff --git a/Linux-PAM/bin/README b/Linux-PAM/bin/README new file mode 100644 index 00000000..427a871a --- /dev/null +++ b/Linux-PAM/bin/README @@ -0,0 +1,30 @@ +## +# $Id: README,v 1.1.1.1 2001/04/29 04:16:25 hartmans Exp $ +## + +(now we are getting networked apps, be careful to try and test on a +securely isolated system!) + +N=2 <-- blank xsh + +Following a 'make install' (which should be done as root) in the +parent directory this directory will contain $N binaries. The source +for these programs is in ../examples. They are various short programs +to use and otherwise test-drive the Linux-PAM libraries/modules with. + +These programs grant no privileges, but they give an idea of how well +the modules are working. + +blank is new as of Linux-PAM-0.21. If you are writing/modifying an +application it might be a place to start... + +xsh is new as of Linux-PAM-0.31, it is identical to blank, but invokes +/bin/sh if the user is authenticated. + +[other apps are to be found in SimplePAMApps and many more on Red +Hat's server.. http://www.redhat.com/] + +Best wishes + +Andrew +(morgan@parc.power.net) diff --git a/Linux-PAM/conf/Makefile b/Linux-PAM/conf/Makefile new file mode 100644 index 00000000..a668607b --- /dev/null +++ b/Linux-PAM/conf/Makefile @@ -0,0 +1,34 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:16:25 hartmans Exp $ +# +# + +dummy: + @echo "*** This is not a top level Makefile!" + +########################################################## + +all: + $(MAKE) -C pam_conv1 all + +install: $(FAKEROOT)$(CONFIGED)/pam.conf + $(MAKE) -C pam_conv1 install + +$(FAKEROOT)$(CONFIGED)/pam.conf: ./pam.conf + bash -f ./install_conf + +remove: + rm -f $(FAKEROOT)$(CONFIGED)/pam.conf + $(MAKE) -C pam_conv1 remove + +check: + bash -f ./md5itall + +lclean: + rm -f core *~ .ignore_age + +clean: lclean + $(MAKE) -C pam_conv1 clean + +extraclean: lclean + $(MAKE) -C pam_conv1 extraclean diff --git a/Linux-PAM/conf/install b/Linux-PAM/conf/install new file mode 100755 index 00000000..2eae3671 --- /dev/null +++ b/Linux-PAM/conf/install @@ -0,0 +1,178 @@ +#!/bin/sh +# +# [This file was lifted from an X distribution. There was no explicit +# copyright in the file, but the following text was associated with it. +# should anyone from the X Consortium wish to alter the following +# text. Please email Thanks. ] +# +# -------------------------- +# The X Consortium maintains and distributes the X Window System and +# related software and documentation in coordinated releases. A release +# consists of two distinct parts: +# +# 1) Specifications and Sample implementations of X Consortium +# standards, and +# +# 2) software and documentation contributed by the general X Consortium +# community. +# +# The timing and contents of a release are determined by the Consortium +# staff based on the needs and desires of the Members and the advice of +# the Advisory Board, tempered by the resource constraints of the +# Consortium. +# +# Members have access to all X Consortium produced software and +# documentation prior to release to the public. Each Member can receive +# pre-releases and public releases at no charge. In addition, Members +# have access to software and documentation while it is under +# development, and can periodically request snapshots of the development +# system at no charge. +# +# The X Consortium also maintains an electronic mail system for +# reporting problems with X Consortium produced software and +# documentation. Members have access to all bug reports, as well as all +# software patches as they are incrementally developed by the Consortium +# staff between releases. +# +# In general, all materials included in X Consortium releases are +# copyrighted and contain permission notices granting unrestricted use, +# sales and redistribution rights provided that the copyrights and the +# permission notices are left intact. All materials are provided "as +# is," without express or implied warranty. +# -------------------------- +# +# This accepts bsd-style install arguments and makes the appropriate calls +# to the System V install. +# + +flags="" +dst="" +src="" +dostrip="" +owner="" +mode="" + +while [ x$1 != x ]; do + case $1 in + -c) shift + continue;; + + -m) flags="$flags $1 $2 " + mode="$2" + shift + shift + continue;; + + -o) flags="$flags -u $2 " + owner="$2" + shift + shift + continue;; + + -g) flags="$flags $1 $2 " + shift + shift + continue;; + + -s) dostrip="strip" + shift + continue;; + + *) if [ x$src = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +case "$mode" in +"") + ;; +*) + case "$owner" in + "") + flags="$flags -u root" + ;; + esac + ;; +esac + +if [ x$src = x ] +then + echo "$0: no input file specified" + exit 1 +fi + +if [ x$dst = x ] +then + echo "$0: no destination specified" + exit 1 +fi + + +# set up some variable to be used later + +rmcmd="" +srcdir="." + +# if the destination isn't a directory we'll need to copy it first + +if [ ! -d $dst ] +then + dstbase=`basename $dst` + cp $src /tmp/$dstbase + rmcmd="rm -f /tmp/$dstbase" + src=$dstbase + srcdir=/tmp + dst="`echo $dst | sed 's,^\(.*\)/.*$,\1,'`" + if [ x$dst = x ] + then + dst="." + fi +fi + + +# If the src file has a directory, copy it to /tmp to make install happy + +srcbase=`basename $src` + +if [ "$src" != "$srcbase" -a "$src" != "./$srcbase" ] +then + cp $src /tmp/$srcbase + src=$srcbase + srcdir=/tmp + rmcmd="rm -f /tmp/$srcbase" +fi + +# do the actual install + +if [ -f /usr/sbin/install ] +then + installcmd=/usr/sbin/install +elif [ -f /etc/install ] +then + installcmd=/etc/install +else + installcmd=install +fi + +# This rm is commented out because some people want to be able to +# install through symbolic links. Uncomment it if it offends you. +rm -f $dst/$srcbase +(cd $srcdir ; $installcmd -f $dst $flags $src) + +if [ x$dostrip = xstrip ] +then + strip $dst/$srcbase +fi + +# and clean up + +$rmcmd + +exit + diff --git a/Linux-PAM/conf/install_conf b/Linux-PAM/conf/install_conf new file mode 100755 index 00000000..7a2acd98 --- /dev/null +++ b/Linux-PAM/conf/install_conf @@ -0,0 +1,36 @@ +#!/bin/sh + +CONFILE="$FAKEROOT"$CONFIGED/pam.conf +IGNORE_AGE=./.ignore_age +CONF=./pam.conf + +echo + +if [ -f "$IGNORE_AGE" ]; then + echo "you don't want to be bothered with the age of your $CONFILE file" + yes="n" +elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then + if [ -f "$CONFILE" ]; then + echo "\ +An older Linux-PAM configuration file already exists ($CONFILE)" + WRITE=overwrite + fi + echo -n "\ +Do you wish to copy the $CONF file in this distribution +to $CONFILE ? (y/n) [n] " + read yes +else + yes=n +fi + +if [ "$yes" = "y" ]; then + echo " copying $CONF to $CONFILE" + cp $CONF $CONFILE +else + touch "$IGNORE_AGE" + echo " Skipping $CONF installation" +fi + +echo + +exit 0 diff --git a/Linux-PAM/conf/md5itall b/Linux-PAM/conf/md5itall new file mode 100755 index 00000000..2f532b31 --- /dev/null +++ b/Linux-PAM/conf/md5itall @@ -0,0 +1,43 @@ +#!/bin/bash +# +# $Id: md5itall,v 1.1.1.1 2001/04/29 04:16:26 hartmans Exp $ +# +# Created by Andrew G. Morgan (morgan@parc.power.net) +# + +MD5SUM=md5sum +CHKFILE1=./.md5sum +CHKFILE2=./.md5sum-new + +which $MD5SUM > /dev/null +result=$? + +if [ -x "$MD5SUM" ] || [ $result -eq 0 ]; then + rm -f $CHKFILE2 + echo -n "computing md5 checksums." + for x in `cat ../.filelist` ; do + (cd ../.. ; $MD5SUM $x) >> $CHKFILE2 + echo -n "." + done + echo + if [ -f "$CHKFILE1" ]; then + echo "\ +---> Note, since the last \`make check', the following file(s) have changed: +===========================================================================" + diff $CHKFILE1 $CHKFILE2 + if [ $? -eq 0 ]; then + echo "\ +--------------------------- Nothing has changed ---------------------------" + fi + echo "\ +===========================================================================" + fi + rm -f "$CHKFILE1" + mv "$CHKFILE2" "$CHKFILE1" + chmod 400 "$CHKFILE1" +else + echo "\ +Please install \`$MD5SUM'. +[It is used to check the integrity of this distribution] +---> no check done." +fi diff --git a/Linux-PAM/conf/mkdirp b/Linux-PAM/conf/mkdirp new file mode 100755 index 00000000..b0e04b05 --- /dev/null +++ b/Linux-PAM/conf/mkdirp @@ -0,0 +1,50 @@ +#!/bin/sh +# +# this is a wrapper for difficult mkdir programs... +# + +for d in $* +do + if [ ! -d $d ]; then + mkdir -p $d + if [ $? -ne 0 ]; then exit $? ; fi + fi +done + +exit 0 + +########################################################################## +# if your mkdir does not support the -p option delete the above lines and +# use what follows: +-------------------- +#!/bin/sh + +#VERBOSE=yes +Cwd=`pwd` + +for d in $* +do + if [ "`echo $d|cut -c1`" != "/" ]; then + x=`pwd`/$d + else + x=$d + fi + x="`echo $x|sed -e 'yX/X X'`" + cd / + for s in $x + do + if [ -d $s ]; then + if [ -n "$VERBOSE" ]; then echo -n "[$s/]"; fi + cd $s + else + mkdir $s + if [ $? -ne 0 ]; then exit $? ; fi + if [ -n "$VERBOSE" ]; then echo -n "$s/"; fi + cd $s + fi + done + if [ -n "$VERBOSE" ]; then echo ; fi + cd $Cwd +done + +exit 0 diff --git a/Linux-PAM/conf/pam.conf b/Linux-PAM/conf/pam.conf new file mode 100644 index 00000000..395b7ba3 --- /dev/null +++ b/Linux-PAM/conf/pam.conf @@ -0,0 +1,126 @@ +# ---------------------------------------------------------------------------# +# /etc/pam.conf # +# # +# Last modified by Andrew G. Morgan # +# ---------------------------------------------------------------------------# +# $Id: pam.conf,v 1.1.1.1 2001/04/29 04:16:26 hartmans Exp $ +# ---------------------------------------------------------------------------# +# serv. module ctrl module [path] ...[args..] # +# name type flag # +# ---------------------------------------------------------------------------# +# +# The PAM configuration file for the `chfn' service +# +chfn auth required pam_unix.so +chfn account required pam_unix.so +chfn password required pam_cracklib.so retry=3 +chfn password required pam_unix.so shadow md5 use_authtok +# +# The PAM configuration file for the `chsh' service +# +chsh auth required pam_unix.so +chsh account required pam_unix.so +chsh password required pam_cracklib.so retry=3 +chsh password required pam_unix.so shadow md5 use_authtok +# +# The PAM configuration file for the `ftp' service +# +ftp auth requisite pam_listfile.so \ + item=user sense=deny file=/etc/ftpusers onerr=succeed +ftp auth requisite pam_shells.so +ftp auth required pam_unix.so +ftp account required pam_unix.so +# +# The PAM configuration file for the `imap' service +# +imap auth required pam_unix.so +imap account required pam_unix.so +# +# The PAM configuration file for the `login' service +# +login auth requisite pam_securetty.so +login auth required pam_unix.so +login auth optional pam_group.so +login account requisite pam_time.so +login account required pam_unix.so +login password required pam_cracklib.so retry=3 +login password required pam_unix.so shadow md5 use_authtok +login session required pam_unix.so +# +# The PAM configuration file for the `netatalk' service +# +netatalk auth required pam_unix.so +netatalk account required pam_unix.so +# +# The PAM configuration file for the `other' service +# +other auth required pam_deny.so +other auth required pam_warn.so +other account required pam_deny.so +other password required pam_deny.so +other password required pam_warn.so +other session required pam_deny.so +# +# The PAM configuration file for the `passwd' service +# +passwd password requisite pam_cracklib.so retry=3 +passwd password required pam_unix.so shadow md5 use_authtok +# +# The PAM configuration file for the `rexec' service +# +rexec auth requisite pam_securetty.so +rexec auth requisite pam_nologin.so +rexec auth sufficient pam_rhosts_auth.so +rexec auth required pam_unix.so +rexec account required pam_unix.so +rexec session required pam_unix.so +rexec session required pam_limits.so +# +# The PAM configuration file for the `rlogin' service +# this application passes control to `login' if it fails +# +rlogin auth requisite pam_securetty.so +rlogin auth requisite pam_nologin.so +rlogin auth required pam_rhosts_auth.so +rlogin account required pam_unix.so +rlogin password required pam_cracklib.so retry=3 +rlogin password required pam_unix.so shadow md5 use_authtok +rlogin session required pam_unix.so +rlogin session required pam_limits.so +# +# The PAM configuration file for the `rsh' service +# +rsh auth requisite pam_securetty.so +rsh auth requisite pam_nologin.so +rsh auth sufficient pam_rhosts_auth.so +rsh auth required pam_unix.so +rsh account required pam_unix.so +rsh session required pam_unix.so +rsh session required pam_limits.so +# +# The PAM configuration file for the `samba' service +# +samba auth required pam_unix.so +samba account required pam_unix.so +# +# The PAM configuration file for the `su' service +# +su auth required pam_wheel.so +su auth sufficient pam_rootok.so +su auth required pam_unix.so +su account required pam_unix.so +su session required pam_unix.so +# +# The PAM configuration file for the `vlock' service +# +vlock auth required pam_unix.so +# +# The PAM configuration file for the `xdm' service +# +xdm auth required pam_unix.so +xdm account required pam_unix.so +# +# The PAM configuration file for the `xlock' service +# +xlock auth required pam_unix.so + diff --git a/Linux-PAM/conf/pam_conv1/Makefile b/Linux-PAM/conf/pam_conv1/Makefile new file mode 100644 index 00000000..f23c8aa6 --- /dev/null +++ b/Linux-PAM/conf/pam_conv1/Makefile @@ -0,0 +1,46 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:22 hartmans Exp $ +# + +include ../../Make.Rules + +# +ifeq ($(OS),solaris) + +clean: + @echo not available in Solaris + +all: + @echo not available in Solaris + +install: + @echo not available in Solaris + +else + +all: pam_conv1 + +pam_conv1: pam_conv.tab.c lex.yy.c + $(CC) -o pam_conv1 pam_conv.tab.c $(LINK_LIBLEX) + +pam_conv.tab.c: pam_conv.y lex.yy.c + bison pam_conv.y + +lex.yy.c: pam_conv.lex + flex pam_conv.lex + +lclean: + rm -f core pam_conv1 lex.yy.c pam_conv.tab.c *.o *~ + rm -rf ./pam.d pam_conv.output + +clean: lclean + +install: pam_conv1 + cp -f ./pam_conv1 ../../bin + +endif + +remove: + rm -f ../../bin/pam_conv1 + +extraclean: remove clean diff --git a/Linux-PAM/conf/pam_conv1/README b/Linux-PAM/conf/pam_conv1/README new file mode 100644 index 00000000..3a750d73 --- /dev/null +++ b/Linux-PAM/conf/pam_conv1/README @@ -0,0 +1,10 @@ +$Id: README,v 1.1.1.1 2001/04/29 04:16:26 hartmans Exp $ + +This directory contains a untility to convert pam.conf files to a pam.d/ +tree. The conversion program takes pam.conf from the standard input and +creates the pam.d/ directory in the current directory. + +The program will fail if ./pam.d/ already exists. + +Andrew Morgan, February 1997 + diff --git a/Linux-PAM/conf/pam_conv1/pam_conv.lex b/Linux-PAM/conf/pam_conv1/pam_conv.lex new file mode 100644 index 00000000..addc60ae --- /dev/null +++ b/Linux-PAM/conf/pam_conv1/pam_conv.lex @@ -0,0 +1,42 @@ + +%{ +/* + * $Id: pam_conv.lex,v 1.1.1.1 2001/04/29 04:16:26 hartmans Exp $ + * + * Copyright (c) Andrew G. Morgan 1997 + * + * This file is covered by the Linux-PAM License (which should be + * distributed with this file.) + */ + + const static char lexid[]= + "$Id: pam_conv.lex,v 1.1.1.1 2001/04/29 04:16:26 hartmans Exp $\n" + "Copyright (c) Andrew G. Morgan 1997 \n"; + + extern int current_line; +%} + +%% + +"#"[^\n]* ; /* skip comments (sorry) */ + +"\\\n" { + ++current_line; +} + +([^\n\t ]|[\\][^\n])+ { + return TOK; +} + +[ \t]+ ; /* Ignore */ + +<> { + return EOFILE; +} + +[\n] { + ++current_line; + return NL; +} + +%% diff --git a/Linux-PAM/conf/pam_conv1/pam_conv.y b/Linux-PAM/conf/pam_conv1/pam_conv.y new file mode 100644 index 00000000..0cbfa5f8 --- /dev/null +++ b/Linux-PAM/conf/pam_conv1/pam_conv.y @@ -0,0 +1,204 @@ +%{ + +/* + * $Id: pam_conv.y,v 1.1.1.2 2002/09/15 20:08:22 hartmans Exp $ + * + * Copyright (c) Andrew G. Morgan 1997 + * + * This file is covered by the Linux-PAM License (which should be + * distributed with this file.) + */ + + const static char bisonid[]= + "$Id: pam_conv.y,v 1.1.1.2 2002/09/15 20:08:22 hartmans Exp $\n" + "Copyright (c) Andrew G. Morgan 1997-8 \n"; + +#include +#include +#include +#include + + int current_line=1; + extern char *yytext; + +/* XXX - later we'll change this to be the specific conf file(s) */ +#define newpamf stderr + +#define PAM_D "./pam.d" +#define PAM_D_MODE 0755 +#define PAM_D_MAGIC_HEADER \ + "#%PAM-1.0\n" \ + "#[For version 1.0 syntax, the above header is optional]\n" + +#define PAM_D_FILE_FMT PAM_D "/%s" + + const char *old_to_new_ctrl_flag(const char *old); + void yyerror(const char *format, ...); +%} + +%union { + int def; + char *string; +} + +%token NL EOFILE TOK + +%type tok path tokenls + +%start complete + +%% + +complete +: +| complete NL +| complete line +| complete EOFILE { + return 0; +} +; + +line +: tok tok tok path tokenls NL { + char *filename; + FILE *conf; + int i; + + /* make sure we have lower case */ + for (i=0; $1[i]; ++i) { + $1[i] = tolower($1[i]); + } + + /* $1 = service-name */ + yyerror("Appending to " PAM_D "/%s", $1); + + filename = malloc(strlen($1) + sizeof(PAM_D) + 6); + sprintf(filename, PAM_D_FILE_FMT, $1); + conf = fopen(filename, "r"); + if (conf == NULL) { + /* new file */ + conf = fopen(filename, "w"); + if (conf != NULL) { + fprintf(conf, PAM_D_MAGIC_HEADER); + fprintf(conf, + "#\n" + "# The PAM configuration file for the `%s' service\n" + "#\n", $1); + } + } else { + fclose(conf); + conf = fopen(filename, "a"); + } + if (conf == NULL) { + yyerror("trouble opening %s - aborting", filename); + exit(1); + } + free(filename); + + /* $2 = module-type */ + fprintf(conf, "%-10s", $2); + free($2); + + /* $3 = required etc. */ + { + const char *trans; + + trans = old_to_new_ctrl_flag($3); + free($3); + fprintf(conf, " %-10s", trans); + } + + /* $4 = module-path */ + fprintf(conf, " %s", $4); + free($4); + + /* $5 = arguments */ + if ($5 != NULL) { + fprintf(conf, " \\\n\t\t%s", $5); + free($5); + } + + /* end line */ + fprintf(conf, "\n"); + + fclose(conf); +} +| error NL { + yyerror("malformed line"); +} +; + +tokenls +: { + $$=NULL; +} +| tokenls tok { + int len; + + if ($1) { + len = strlen($1) + strlen($2) + 2; + $$ = malloc(len); + sprintf($$,"%s %s",$1,$2); + free($1); + free($2); + } else { + $$ = $2; + } +} +; + +path +: TOK { + /* XXX - this could be used to check if file present */ + $$ = strdup(yytext); +} + +tok +: TOK { + $$ = strdup(yytext); +} + +%% + +#include "lex.yy.c" + +const char *old_to_new_ctrl_flag(const char *old) +{ + static const char *clist[] = { + "requisite", + "required", + "sufficient", + "optional", + NULL, + }; + int i; + + for (i=0; clist[i]; ++i) { + if (strcasecmp(clist[i], old) == 0) { + break; + } + } + + return clist[i]; +} + +void yyerror(const char *format, ...) +{ + va_list args; + + fprintf(stderr, "line %d: ", current_line); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} + +int main(int argc, char *argv[]) +{ + if (mkdir(PAM_D, PAM_D_MODE) != 0) { + yyerror(PAM_D " already exists.. aborting"); + exit(1); + } + yyparse(); + exit(0); +} diff --git a/Linux-PAM/configure b/Linux-PAM/configure new file mode 100755 index 00000000..270184c7 --- /dev/null +++ b/Linux-PAM/configure @@ -0,0 +1,3887 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_default_prefix= +ac_help="$ac_help + --enable-debug specify you are building with debugging on" +ac_help="$ac_help + --enable-memory-debug specify you want every malloc etc. call tracked" +ac_help="$ac_help + --enable-libdebug specify you are building debugging libraries" +ac_help="$ac_help + --enable-fakeroot=" +ac_help="$ac_help + --enable-securedir= [default \$libdir/security]" +ac_help="$ac_help + --enable-sconfigdir= [default \$sysconfdir/security]" +ac_help="$ac_help + --enable-suplementedir= [default \$sbindir]" +ac_help="$ac_help + --enable-includedir= - where to put " +ac_help="$ac_help + --enable-docdir=" +ac_help="$ac_help + --enable-mandir=" +ac_help="$ac_help + --enable-pamlocking configure libpam to observe a global authentication lock" +ac_help="$ac_help + --enable-uglyhack configure libpam to try to honor old pam_strerror syntax" +ac_help="$ac_help + --enable-read-both-confs read both /etc/pam.d and /etc/pam.conf files" +ac_help="$ac_help + --enable-static-libpam build a libpam.a library" +ac_help="$ac_help + --disable-dynamic-libpam do not build a shared libpam library" +ac_help="$ac_help + --enable-static-modules do not make the modules dynamically loadable" +ac_help="$ac_help + --disable-lckpwdf do not use the lckpwdf function" +ac_help="$ac_help + --with-mailspool path to mail spool directory + [default _PATH_MAILDIR if defined in paths.h, otherwise /var/spool/mail]" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=conf/pam_conv1/pam_conv.y + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + + +LIBPAM_VERSION_MAJOR=0 +LIBPAM_VERSION_MINOR=76 + + + +cat >> confdefs.h <<\EOF +#define LIBPAM_VERSION_MAJOR 1 +EOF + +cat >> confdefs.h <<\EOF +#define LIBPAM_VERSION_MINOR 1 +EOF + + + + + +LOCALSRCDIR=`/bin/pwd` ; +LOCALOBJDIR=`/bin/pwd` ; +OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + + + +CONF_CFLAGS= ; +MKDIR="mkdir -p" ; + +SHLIBMODE=755 ; + +USESONAME=yes ; +SOSWITCH=-soname ; +NEEDSONAME=no ; +LDCONFIG=/sbin/ldconfig ; + +if test "$OS" = "aix"; then + INSTALL=/usr/ucb/install -c +else + INSTALL=/usr/bin/install +fi + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:610: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:640: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:691: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:723: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 734 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:739: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:765: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:770: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:798: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:834: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:867: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:901: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:943: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:964: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + WITH_DEBUG=yes ; cat >> confdefs.h <<\EOF +#define DEBUG 1 +EOF + +else + WITH_DEBUG=no +fi + + + +# Check whether --enable-memory-debug or --disable-memory-debug was given. +if test "${enable_memory_debug+set}" = set; then + enableval="$enable_memory_debug" + WITH_MEMORY_DEBUG=yes ; cat >> confdefs.h <<\EOF +#define MEMORY_DEBUG 1 +EOF + +else + WITH_MEMORY_DEBUG=no +fi + + + +# Check whether --enable-libdebug or --disable-libdebug was given. +if test "${enable_libdebug+set}" = set; then + enableval="$enable_libdebug" + WITH_LIBDEBUG=yes ; cat >> confdefs.h <<\EOF +#define WITH_LIBDEBUG 1 +EOF + +else + WITH_LIBDEBUG=no +fi + + + +# Check whether --enable-fakeroot or --disable-fakeroot was given. +if test "${enable_fakeroot+set}" = set; then + enableval="$enable_fakeroot" + FAKEROOT=$enableval +fi + + + +# Check whether --enable-securedir or --disable-securedir was given. +if test "${enable_securedir+set}" = set; then + enableval="$enable_securedir" + SECUREDIR=$enableval +else + SECUREDIR=$libdir/security +fi + + + +# Check whether --enable-sconfigdir or --disable-sconfigdir was given. +if test "${enable_sconfigdir+set}" = set; then + enableval="$enable_sconfigdir" + SCONFIGDIR=$enableval +else + SCONFIGDIR=$sysconfdir/security +fi + + + +# Check whether --enable-suplementedir or --disable-suplementedir was given. +if test "${enable_suplementedir+set}" = set; then + enableval="$enable_suplementedir" + SUPLEMENTED=$enableval +else + SUPLEMENTED=$sbindir +fi + + + +# Check whether --enable-includedir or --disable-includedir was given. +if test "${enable_includedir+set}" = set; then + enableval="$enable_includedir" + INCLUDEDIR=$enableval +else + INCLUDEDIR=/usr/include +fi + + + +# Check whether --enable-docdir or --disable-docdir was given. +if test "${enable_docdir+set}" = set; then + enableval="$enable_docdir" + DOCDIR=$enableval +else + DOCDIR=/usr/share/doc/pam +fi + + + +# Check whether --enable-mandir or --disable-mandir was given. +if test "${enable_mandir+set}" = set; then + enableval="$enable_mandir" + MANDIR=$enableval +else + MANDIR=/usr/share/man +fi + + + +# Check whether --enable-pamlocking or --disable-pamlocking was given. +if test "${enable_pamlocking+set}" = set; then + enableval="$enable_pamlocking" + WITH_PAMLOCKING=yes ; cat >> confdefs.h <<\EOF +#define PAM_LOCKING 1 +EOF + +else + WITH_PAMLOCKING=no +fi + + + +# Check whether --enable-uglyhack or --disable-uglyhack was given. +if test "${enable_uglyhack+set}" = set; then + enableval="$enable_uglyhack" + cat >> confdefs.h <<\EOF +#define UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT 1 +EOF + +fi + + +# Check whether --enable-read-both-confs or --disable-read-both-confs was given. +if test "${enable_read_both_confs+set}" = set; then + enableval="$enable_read_both_confs" + cat >> confdefs.h <<\EOF +#define PAM_READ_BOTH_CONFS 1 +EOF + +fi + + + +# Check whether --enable-static-libpam or --disable-static-libpam was given. +if test "${enable_static_libpam+set}" = set; then + enableval="$enable_static_libpam" + STATIC_LIBPAM=yes +else + STATIC_LIBPAM=no +fi + + + +# Check whether --enable-dynamic-libpam or --disable-dynamic-libpam was given. +if test "${enable_dynamic_libpam+set}" = set; then + enableval="$enable_dynamic_libpam" + DYNAMIC_LIBPAM=no +else + DYNAMIC_LIBPAM=yes +fi + + + +DYNAMIC=-DPAM_DYNAMIC + + +# Check whether --enable-static-modules or --disable-static-modules was given. +if test "${enable_static_modules+set}" = set; then + enableval="$enable_static_modules" + STATIC=-DPAM_STATIC +fi + + + +# Check whether --enable-lckpwdf or --disable-lckpwdf was given. +if test "${enable_lckpwdf+set}" = set; then + enableval="$enable_lckpwdf" + WITH_LCKPWDF=no +else + WITH_LCKPWDF=yes +fi + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1175: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1196: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1213: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1230: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in paths.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1258: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1268: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +# Check whether --with-mailspool or --without-mailspool was given. +if test "${with_mailspool+set}" = set; then + withval="$with_mailspool" + with_mailspool=${withval} +fi + +if test x$with_mailspool != x ; then + pam_mail_spool="\"$with_mailspool\"" +else + if test "$cross_compiling" = yes; then + pam_mail_spool="\"/var/spool/mail\"" +else + cat > conftest.$ac_ext < +int main() { +#ifdef _PATH_MAILDIR +exit(0); +#else +exit(1); +#endif +} +EOF +if { (eval echo configure:1319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + pam_mail_spool="_PATH_MAILDIR" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + pam_mail_spool="\"/var/spool/mail\"" +fi +rm -fr conftest* +fi + +fi +cat >> confdefs.h <&6 +echo "configure:1338: checking for __libc_sched_setscheduler in -lc" >&5 +ac_lib_var=`echo c'_'__libc_sched_setscheduler | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + PAM_NEEDS_LIBC= +else + echo "$ac_t""no" 1>&6 +PAM_NEEDS_LIBC=-lc +fi + + + +echo $ac_n "checking for lckpwdf in -lc""... $ac_c" 1>&6 +echo "configure:1381: checking for lckpwdf in -lc" >&5 +ac_lib_var=`echo c'_'lckpwdf | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LCKPWDF=yes +else + echo "$ac_t""no" 1>&6 +HAVE_LCKPWDF=no +fi + + + +echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "configure:1424: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBDL=-ldl +else + echo "$ac_t""no" 1>&6 +fi + + + +echo $ac_n "checking for FascistCheck in -lcrack""... $ac_c" 1>&6 +echo "configure:1466: checking for FascistCheck in -lcrack" >&5 +ac_lib_var=`echo crack'_'FascistCheck | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrack $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBCRACK=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBCRACK 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBCRACK=no +fi + + + +echo $ac_n "checking for fcrypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:1512: checking for fcrypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'fcrypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBCRYPT=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBCRYPT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBCRYPT=no +fi + + +echo $ac_n "checking for logwtmp in -lutil""... $ac_c" 1>&6 +echo "configure:1557: checking for logwtmp in -lutil" >&5 +ac_lib_var=`echo util'_'logwtmp | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lutil $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBUTIL=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBUTIL 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBUTIL=no +fi + + +echo $ac_n "checking for dbm_store in -lndbm""... $ac_c" 1>&6 +echo "configure:1602: checking for dbm_store in -lndbm" >&5 +ac_lib_var=`echo ndbm'_'dbm_store | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lndbm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBNDBM=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBNDBM 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBNDBM=no +fi + + +echo $ac_n "checking for dbm_store in -ldb""... $ac_c" 1>&6 +echo "configure:1647: checking for dbm_store in -ldb" >&5 +ac_lib_var=`echo db'_'dbm_store | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldb $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBDB=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBDB 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBDB=no +fi + +if test x$HAVE_LIBDB != xyes ; then + echo $ac_n "checking for db_create in -ldb""... $ac_c" 1>&6 +echo "configure:1692: checking for db_create in -ldb" >&5 +ac_lib_var=`echo db'_'db_create | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldb $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBDB=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBDB 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBDB=no +fi + +fi + +echo $ac_n "checking for yylex in -lfl""... $ac_c" 1>&6 +echo "configure:1738: checking for yylex in -lfl" >&5 +ac_lib_var=`echo fl'_'yylex | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lfl HAVE_LIBFL=no $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + yyterminate +else + echo "$ac_t""no" 1>&6 +HAVE_LIBFL=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBFL 1 +EOF + +fi + + +echo $ac_n "checking for yp_maplist in -lnsl""... $ac_c" 1>&6 +echo "configure:1783: checking for yp_maplist in -lnsl" >&5 +ac_lib_var=`echo nsl'_'yp_maplist | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBNSL=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBNSL 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBNSL=no +fi + + +echo $ac_n "checking for pwdb_db_name in -lpwdb""... $ac_c" 1>&6 +echo "configure:1828: checking for pwdb_db_name in -lpwdb" >&5 +ac_lib_var=`echo pwdb'_'pwdb_db_name | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lpwdb $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBPWDB=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBPWDB 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBPWDB=no +fi + + +echo $ac_n "checking for yywrap in -lfl""... $ac_c" 1>&6 +echo "configure:1873: checking for yywrap in -lfl" >&5 +ac_lib_var=`echo fl'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lfl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBFLEX=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBFLEX 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBFLEX=no +fi + + +echo $ac_n "checking for yywrap in -ll""... $ac_c" 1>&6 +echo "configure:1918: checking for yywrap in -ll" >&5 +ac_lib_var=`echo l'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ll $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBLEX=yes ; cat >> confdefs.h <<\EOF +#define HAVE_LIBLEX 1 +EOF + +else + echo "$ac_t""no" 1>&6 +HAVE_LIBLEX=no +fi + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1968: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1981: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:2006: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:2047: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2089: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2102: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2169: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:2193: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:2214: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h sys/fsuid.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2238: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2248: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in features.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2279: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in crypt.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2320: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2330: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in ndbm.h db.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2361: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2371: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +HAVE_NDBM_H=$ac_cv_header_ndbm_h + + +for ac_hdr in lastlog.h utmp.h utmpx.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2404: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2414: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + + +echo $ac_n "checking path to cracklib dictionary""... $ac_c" 1>&6 +echo "configure:2443: checking path to cracklib dictionary" >&5 +DICT_DIR_CANDIDATES="/usr/lib /usr/share/dict /usr/share/lib \ + /usr/local/lib /usr/local/share/lib" +DICT_FILE_CANDIDATES="pw_dict cracklib_dict" +CRACKLIB_DICTPATH="" +for d in $DICT_DIR_CANDIDATES ; do + for f in $DICT_FILE_CANDIDATES ; do + if test -r $d/$f.hwm ; then + CRACKLIB_DICTPATH=$d/$f + break 2 + elif test -r $d/dict/$f.hwm ; then + CRACKLIB_DICTPATH=$d/dict/$f + break 2 + fi + done +done +if test -z "$CRACKLIB_DICTPATH" ; then + echo "$ac_t""none found" 1>&6 +else + echo "$ac_t""$CRACKLIB_DICTPATH" 1>&6 +fi + + + +GCC_WARNINGS="-Wall -Wwrite-strings \ + -Wpointer-arith -Wcast-qual -Wcast-align \ + -Wstrict-prototypes -Wmissing-prototypes \ + -Wnested-externs -Winline -Wshadow" + +if test "$GCC" = yes; then + CC=gcc ; +### May need per-OS attention +### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris. + case $OS in + linux) + OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic" + LD_D="gcc -shared -Xlinker -x" + WARNINGS="$GCC_WARNINGS" + PIC="-fPIC" + DYNTYPE=so + LD=ld + LD_L="$LD -x -shared" + RANLIB=ranlib + STRIP=strip + CC_STATIC="-Xlinker -export-dynamic" + ;; + sunos) + OS_CFLAGS="-ansi -pedantic" + LD_D="gcc -shared -Xlinker -x" + WARNINGS="$GCC_WARNINGS" + PIC="-fPIC" + DYNTYPE=so + LD=ld + LD_L="$LD -x -shared" + RANLIB=ranlib + STRIP=strip + CC_STATIC="-Xlinker -export-dynamic" + ;; + aix) + OS_CFLAGS="" + DYNTYPE=lo + LD=ld + LD_L=ld -bexpall -bM:SRE -bnoentry + LD_D="$LD_L" + RANLIB=ranlib + STRIP=strip + ;; + *) + OS_CFLAGS="" + ;; + esac +else +### +### Non-gcc needs attention on per-OS basis +### + case "$OS" in + darwin) +# add some stuff here (see sourceforge bug 534205) +# DOCDIR=/System/Documentation/Administration/Libraries/PAM +# MANDIR=/usr/share/man + ;; + solaris) + ### Support for Solaris-C + OS_CFLAGS="" + WARNINGS="" + PIC="-K pic" + LD=ld + LD_D="cc -z text -G -R." + LD_L="$LD_D" + RANLIB=ranlib + STRIP=strip + CC_STATIC= + ;; + irix*) + OSRELEASE=`uname -r` + if test "$OSRELEASE" = 6.5; then + OS_CFLAGS="" + WARNINGS="-fullwarn" + PIC= #PIC code is default for IRIX + LD="cc -shared" # modules friendly approach + LD_D="cc -shared" + LD_L="ld -G -z redlocsym" + RANLIB=echo + STRIP=strip + CC_STATIC= + else + echo "IRIX prior to 6.5 not allowed for" + exit + fi + ;; + *) echo "Native compiler on $OS is not yet supported" + exit + ;; + esac +fi + + + + + + + + + + + + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:2571: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext < +#include +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:2589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext < +#include +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:2604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2661: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:2736: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:2770: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2803: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2836: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2869: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2883: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2904: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2917: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + + +echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 +echo "configure:2939: checking type of array argument to getgroups" >&5 +if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_type_getgroups=cross +else + cat > conftest.$ac_ext < +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +main() +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short but getgroups modifies an array of ints. */ + exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); +} + +EOF +if { (eval echo configure:2972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_type_getgroups=gid_t +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_type_getgroups=int +fi +rm -fr conftest* +fi + +if test $ac_cv_type_getgroups = cross; then + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_getgroups=gid_t +else + rm -rf conftest* + ac_cv_type_getgroups=int +fi +rm -f conftest* + +fi +fi + +echo "$ac_t""$ac_cv_type_getgroups" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3011: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:3057: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:3093: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:3145: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3173: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_func in gethostname gettimeofday mkdir select strcspn strdup strerror strspn strstr strtol uname +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3200: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3228: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +for ac_func in getpwnam_r getgrnam_r +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3256: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Extract the first word of "sgml2txt", so it can be a program name with args. +set dummy sgml2txt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3312: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2TXT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HAVE_SGML2TXT"; then + ac_cv_prog_HAVE_SGML2TXT="$HAVE_SGML2TXT" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HAVE_SGML2TXT="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_HAVE_SGML2TXT" && ac_cv_prog_HAVE_SGML2TXT="no" +fi +fi +HAVE_SGML2TXT="$ac_cv_prog_HAVE_SGML2TXT" +if test -n "$HAVE_SGML2TXT"; then + echo "$ac_t""$HAVE_SGML2TXT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "sgml2html", so it can be a program name with args. +set dummy sgml2html; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3342: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2HTML'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HAVE_SGML2HTML"; then + ac_cv_prog_HAVE_SGML2HTML="$HAVE_SGML2HTML" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HAVE_SGML2HTML="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_HAVE_SGML2HTML" && ac_cv_prog_HAVE_SGML2HTML="no" +fi +fi +HAVE_SGML2HTML="$ac_cv_prog_HAVE_SGML2HTML" +if test -n "$HAVE_SGML2HTML"; then + echo "$ac_t""$HAVE_SGML2HTML" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "sgml2latex", so it can be a program name with args. +set dummy sgml2latex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3372: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2LATEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HAVE_SGML2LATEX"; then + ac_cv_prog_HAVE_SGML2LATEX="$HAVE_SGML2LATEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HAVE_SGML2LATEX="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_HAVE_SGML2LATEX" && ac_cv_prog_HAVE_SGML2LATEX="no" +fi +fi +HAVE_SGML2LATEX="$ac_cv_prog_HAVE_SGML2LATEX" +if test -n "$HAVE_SGML2LATEX"; then + echo "$ac_t""$HAVE_SGML2LATEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test $HAVE_SGML2LATEX = "yes" ; then + if sgml2latex -h | grep -e --paper | grep ' -p ' > /dev/null ; then + PSER="sgml2latex -o ps" + else + PSER="sgml2latex -p" + fi + # Extract the first word of "ps2pdf", so it can be a program name with args. +set dummy ps2pdf; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3408: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HAVE_PS2PDF'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HAVE_PS2PDF"; then + ac_cv_prog_HAVE_PS2PDF="$HAVE_PS2PDF" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HAVE_PS2PDF="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_HAVE_PS2PDF" && ac_cv_prog_HAVE_PS2PDF="no" +fi +fi +HAVE_PS2PDF="$ac_cv_prog_HAVE_PS2PDF" +if test -n "$HAVE_PS2PDF"; then + echo "$ac_t""$HAVE_PS2PDF" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + # Extract the first word of "sgml2ps", so it can be a program name with args. +set dummy sgml2ps; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3439: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2PS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HAVE_SGML2PS"; then + ac_cv_prog_HAVE_SGML2PS="$HAVE_SGML2PS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HAVE_SGML2PS="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_HAVE_SGML2PS" && ac_cv_prog_HAVE_SGML2PS="no" +fi +fi +HAVE_SGML2PS="$ac_cv_prog_HAVE_SGML2PS" +if test -n "$HAVE_SGML2PS"; then + echo "$ac_t""$HAVE_SGML2PS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test $HAVE_SGML2PS = yes ; then + PSER="sgml2ps" + fi +fi + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "Make.Rules _pam_aconf.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@LIBPAM_VERSION_MAJOR@%$LIBPAM_VERSION_MAJOR%g +s%@LIBPAM_VERSION_MINOR@%$LIBPAM_VERSION_MINOR%g +s%@LOCALSRCDIR@%$LOCALSRCDIR%g +s%@LOCALOBJDIR@%$LOCALOBJDIR%g +s%@OS@%$OS%g +s%@CONF_CFLAGS@%$CONF_CFLAGS%g +s%@MKDIR@%$MKDIR%g +s%@SHLIBMODE@%$SHLIBMODE%g +s%@USESONAME@%$USESONAME%g +s%@SOSWITCH@%$SOSWITCH%g +s%@NEEDSONAME@%$NEEDSONAME%g +s%@LDCONFIG@%$LDCONFIG%g +s%@INSTALL@%$INSTALL%g +s%@CC@%$CC%g +s%@YACC@%$YACC%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@LN_S@%$LN_S%g +s%@SET_MAKE@%$SET_MAKE%g +s%@WITH_DEBUG@%$WITH_DEBUG%g +s%@WITH_MEMORY_DEBUG@%$WITH_MEMORY_DEBUG%g +s%@WITH_LIBDEBUG@%$WITH_LIBDEBUG%g +s%@FAKEROOT@%$FAKEROOT%g +s%@SECUREDIR@%$SECUREDIR%g +s%@SCONFIGDIR@%$SCONFIGDIR%g +s%@SUPLEMENTED@%$SUPLEMENTED%g +s%@INCLUDEDIR@%$INCLUDEDIR%g +s%@DOCDIR@%$DOCDIR%g +s%@MANDIR@%$MANDIR%g +s%@WITH_PAMLOCKING@%$WITH_PAMLOCKING%g +s%@PAM_READ_BOTH_CONFS@%$PAM_READ_BOTH_CONFS%g +s%@STATIC_LIBPAM@%$STATIC_LIBPAM%g +s%@DYNAMIC_LIBPAM@%$DYNAMIC_LIBPAM%g +s%@DYNAMIC@%$DYNAMIC%g +s%@STATIC@%$STATIC%g +s%@WITH_LCKPWDF@%$WITH_LCKPWDF%g +s%@CPP@%$CPP%g +s%@PAM_NEEDS_LIBC@%$PAM_NEEDS_LIBC%g +s%@HAVE_LCKPWDF@%$HAVE_LCKPWDF%g +s%@LIBDL@%$LIBDL%g +s%@HAVE_LIBCRACK@%$HAVE_LIBCRACK%g +s%@HAVE_LIBCRYPT@%$HAVE_LIBCRYPT%g +s%@HAVE_LIBUTIL@%$HAVE_LIBUTIL%g +s%@HAVE_LIBNDBM@%$HAVE_LIBNDBM%g +s%@HAVE_LIBDB@%$HAVE_LIBDB%g +s%@HAVE_LIBFL@%$HAVE_LIBFL%g +s%@HAVE_LIBNSL@%$HAVE_LIBNSL%g +s%@HAVE_LIBPWDB@%$HAVE_LIBPWDB%g +s%@HAVE_LIBFLEX@%$HAVE_LIBFLEX%g +s%@HAVE_LIBLEX@%$HAVE_LIBLEX%g +s%@HAVE_NDBM_H@%$HAVE_NDBM_H%g +s%@CRACKLIB_DICTPATH@%$CRACKLIB_DICTPATH%g +s%@DYNTYPE@%$DYNTYPE%g +s%@OS_CFLAGS@%$OS_CFLAGS%g +s%@WARNINGS@%$WARNINGS%g +s%@PIC@%$PIC%g +s%@LD@%$LD%g +s%@LD_D@%$LD_D%g +s%@LD_L@%$LD_L%g +s%@RANLIB@%$RANLIB%g +s%@STRIP@%$STRIP%g +s%@CC_STATIC@%$CC_STATIC%g +s%@LIBOBJS@%$LIBOBJS%g +s%@HAVE_SGML2TXT@%$HAVE_SGML2TXT%g +s%@HAVE_SGML2HTML@%$HAVE_SGML2HTML%g +s%@HAVE_SGML2LATEX@%$HAVE_SGML2LATEX%g +s%@HAVE_PS2PDF@%$HAVE_PS2PDF%g +s%@HAVE_SGML2PS@%$HAVE_SGML2PS%g +s%@PSER@%$PSER%g +s%@PS2PDF@%$PS2PDF%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/Linux-PAM/configure.in b/Linux-PAM/configure.in new file mode 100644 index 00000000..8da11c85 --- /dev/null +++ b/Linux-PAM/configure.in @@ -0,0 +1,439 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(conf/pam_conv1/pam_conv.y) + +dnl The configuration header file +AC_CONFIG_HEADER(_pam_aconf.h) + +dnl +dnl Release specific +dnl + +LIBPAM_VERSION_MAJOR=0 +LIBPAM_VERSION_MINOR=76 + +AC_SUBST(LIBPAM_VERSION_MAJOR) +AC_SUBST(LIBPAM_VERSION_MINOR) +AC_DEFINE(LIBPAM_VERSION_MAJOR) +AC_DEFINE(LIBPAM_VERSION_MINOR) + +dnl +dnl By default, everything under PAM is installed under the root fs. +dnl + +AC_PREFIX_DEFAULT() + +dnl +dnl Useful info (believed to be portable) - in the future +dnl the LOCALSRCDIR and LOCALOBJDIRs may be different +dnl +LOCALSRCDIR=`/bin/pwd` ; AC_SUBST(LOCALSRCDIR) +LOCALOBJDIR=`/bin/pwd` ; AC_SUBST(LOCALOBJDIR) +OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` +AC_SUBST(OS) + +dnl +dnl Rules needed for the following (hardcoded Linux defaults for now) +dnl + +CONF_CFLAGS= ; AC_SUBST(CONF_CFLAGS) +MKDIR="mkdir -p" ; AC_SUBST(MKDIR) + +SHLIBMODE=755 ; AC_SUBST(SHLIBMODE) + +dnl These are most likely platform specific - I think HPUX differs +USESONAME=yes ; AC_SUBST(USESONAME) +SOSWITCH=-soname ; AC_SUBST(SOSWITCH) +NEEDSONAME=no ; AC_SUBST(NEEDSONAME) +LDCONFIG=/sbin/ldconfig ; AC_SUBST(LDCONFIG) + +dnl ### Should enable this INSTALL detection. +dnl ### Would need to distribute GNU's config.guess and config.sub +dnl AC_PROG_INSTALL +if test "$OS" = "aix"; then + INSTALL=/usr/ucb/install -c +else + INSTALL=/usr/bin/install +fi +AC_SUBST(INSTALL) + +dnl Checks for programs. +AC_PROG_CC +dnl ### AC_PROG_CXX +AC_PROG_YACC +AC_PROG_LEX +dnl AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +dnl +dnl options and defaults +dnl + +dnl lots of debugging information goes to /tmp/pam-debug.log +AC_ARG_ENABLE(debug, +[ --enable-debug specify you are building with debugging on], + WITH_DEBUG=yes ; AC_DEFINE(DEBUG) , WITH_DEBUG=no) +AC_SUBST(WITH_DEBUG) + +AC_ARG_ENABLE(memory-debug, +[ --enable-memory-debug specify you want every malloc etc. call tracked], + WITH_MEMORY_DEBUG=yes ; AC_DEFINE(MEMORY_DEBUG) , WITH_MEMORY_DEBUG=no) +AC_SUBST(WITH_MEMORY_DEBUG) + +dnl build specially named libraries (for debugging purposes) +AC_ARG_ENABLE(libdebug, +[ --enable-libdebug specify you are building debugging libraries], + WITH_LIBDEBUG=yes ; AC_DEFINE(WITH_LIBDEBUG) , WITH_LIBDEBUG=no) +AC_SUBST(WITH_LIBDEBUG) + +dnl packaging convenience +AC_ARG_ENABLE(fakeroot, +[ --enable-fakeroot=], FAKEROOT=$enableval) +AC_SUBST(FAKEROOT) + +AC_ARG_ENABLE(securedir, +[ --enable-securedir= [default \$libdir/security]], + SECUREDIR=$enableval, SECUREDIR=$libdir/security) +AC_SUBST(SECUREDIR) + +AC_ARG_ENABLE(sconfigdir, +[ --enable-sconfigdir= [default \$sysconfdir/security]], + SCONFIGDIR=$enableval, SCONFIGDIR=$sysconfdir/security) +AC_SUBST(SCONFIGDIR) + +AC_ARG_ENABLE(suplementedir, +[ --enable-suplementedir= [default \$sbindir]], + SUPLEMENTED=$enableval, SUPLEMENTED=$sbindir) +AC_SUBST(SUPLEMENTED) + +AC_ARG_ENABLE(includedir, +[ --enable-includedir= - where to put ], + INCLUDEDIR=$enableval, INCLUDEDIR=/usr/include) +AC_SUBST(INCLUDEDIR) + +AC_ARG_ENABLE(docdir, +[ --enable-docdir=], + DOCDIR=$enableval, DOCDIR=/usr/share/doc/pam) +AC_SUBST(DOCDIR) + +AC_ARG_ENABLE(mandir, +[ --enable-mandir=], + MANDIR=$enableval, MANDIR=/usr/share/man) +AC_SUBST(MANDIR) + +AC_ARG_ENABLE(pamlocking, +[ --enable-pamlocking configure libpam to observe a global authentication lock], + WITH_PAMLOCKING=yes ; AC_DEFINE(PAM_LOCKING) , WITH_PAMLOCKING=no) +AC_SUBST(WITH_PAMLOCKING) + +AC_ARG_ENABLE(uglyhack, +[ --enable-uglyhack configure libpam to try to honor old pam_strerror syntax], + AC_DEFINE(UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT)) + +AC_ARG_ENABLE(read-both-confs, +[ --enable-read-both-confs read both /etc/pam.d and /etc/pam.conf files], + AC_DEFINE(PAM_READ_BOTH_CONFS)) +AC_SUBST(PAM_READ_BOTH_CONFS) + +AC_ARG_ENABLE(static-libpam, [ --enable-static-libpam build a libpam.a library], + STATIC_LIBPAM=yes , STATIC_LIBPAM=no) +AC_SUBST(STATIC_LIBPAM) + +AC_ARG_ENABLE(dynamic-libpam, +[ --disable-dynamic-libpam do not build a shared libpam library], + DYNAMIC_LIBPAM=no, DYNAMIC_LIBPAM=yes) +AC_SUBST(DYNAMIC_LIBPAM) + +DYNAMIC=-DPAM_DYNAMIC +AC_SUBST(DYNAMIC) + +AC_ARG_ENABLE(static-modules, +[ --enable-static-modules do not make the modules dynamically loadable], + STATIC=-DPAM_STATIC) +AC_SUBST(STATIC) + +AC_ARG_ENABLE(lckpwdf, +[ --disable-lckpwdf do not use the lckpwdf function], + WITH_LCKPWDF=no, WITH_LCKPWDF=yes) +AC_SUBST(WITH_LCKPWDF) + +AC_CHECK_HEADERS(paths.h) +AC_ARG_WITH(mailspool, +[ --with-mailspool path to mail spool directory + [default _PATH_MAILDIR if defined in paths.h, otherwise /var/spool/mail]], +with_mailspool=${withval}) +if test x$with_mailspool != x ; then + pam_mail_spool="\"$with_mailspool\"" +else + AC_TRY_RUN([ +#include +int main() { +#ifdef _PATH_MAILDIR +exit(0); +#else +exit(1); +#endif +}], pam_mail_spool="_PATH_MAILDIR", +pam_mail_spool="\"/var/spool/mail\"", +pam_mail_spool="\"/var/spool/mail\"") +fi +AC_DEFINE_UNQUOTED(PAM_PATH_MAILDIR, $pam_mail_spool) + +dnl Checks for libraries. +AC_CHECK_LIB(c, __libc_sched_setscheduler, PAM_NEEDS_LIBC=, PAM_NEEDS_LIBC=-lc) +AC_SUBST(PAM_NEEDS_LIBC) + +dnl Checks for the existence of lckpwdf in libc +AC_CHECK_LIB(c, lckpwdf, HAVE_LCKPWDF=yes, HAVE_LCKPWDF=no) +AC_SUBST(HAVE_LCKPWDF) + +dnl Checks for the existence of libdl - on BSD and Tru64 its part of libc +AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl) +AC_SUBST(LIBDL) + +dnl +dnl At least on Solaris, the existing libcrack must be dynamic. +dnl Ought to introduce a check for this. +dnl +AC_CHECK_LIB(crack, FascistCheck, HAVE_LIBCRACK=yes ; AC_DEFINE(HAVE_LIBCRACK), + HAVE_LIBCRACK=no) +AC_SUBST(HAVE_LIBCRACK) + +AC_CHECK_LIB(crypt, fcrypt, HAVE_LIBCRYPT=yes ; AC_DEFINE(HAVE_LIBCRYPT), + HAVE_LIBCRYPT=no) +AC_SUBST(HAVE_LIBCRYPT) +AC_CHECK_LIB(util, logwtmp, HAVE_LIBUTIL=yes ; AC_DEFINE(HAVE_LIBUTIL), + HAVE_LIBUTIL=no) +AC_SUBST(HAVE_LIBUTIL) +AC_CHECK_LIB(ndbm, dbm_store, HAVE_LIBNDBM=yes ; AC_DEFINE(HAVE_LIBNDBM), + HAVE_LIBNDBM=no) +AC_SUBST(HAVE_LIBNDBM) +AC_CHECK_LIB(db, dbm_store, HAVE_LIBDB=yes ; AC_DEFINE(HAVE_LIBDB), + HAVE_LIBDB=no) +if test x$HAVE_LIBDB != xyes ; then + AC_CHECK_LIB(db, db_create, HAVE_LIBDB=yes ; AC_DEFINE(HAVE_LIBDB), + HAVE_LIBDB=no) +fi +AC_SUBST(HAVE_LIBDB) +AC_CHECK_LIB(fl, yylex, yyterminate, HAVE_LIBFL=yes ; AC_DEFINE(HAVE_LIBFL), + HAVE_LIBFL=no) +AC_SUBST(HAVE_LIBFL) +AC_CHECK_LIB(nsl, yp_maplist, HAVE_LIBNSL=yes ; AC_DEFINE(HAVE_LIBNSL), + HAVE_LIBNSL=no) +AC_SUBST(HAVE_LIBNSL) +AC_CHECK_LIB(pwdb, pwdb_db_name, HAVE_LIBPWDB=yes ; AC_DEFINE(HAVE_LIBPWDB), + HAVE_LIBPWDB=no) +AC_SUBST(HAVE_LIBPWDB) +AC_CHECK_LIB(fl, yywrap, HAVE_LIBFLEX=yes ; AC_DEFINE(HAVE_LIBFLEX), + HAVE_LIBFLEX=no) +AC_SUBST(HAVE_LIBFLEX) +AC_CHECK_LIB(l, yywrap, HAVE_LIBLEX=yes ; AC_DEFINE(HAVE_LIBLEX), + HAVE_LIBLEX=no) +AC_SUBST(HAVE_LIBLEX) + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h sys/fsuid.h) + +dnl Linux wants features.h in some of the source files. +AC_CHECK_HEADERS(features.h) + +dnl For module/pam_cracklib +AC_CHECK_HEADERS(crypt.h) + +dnl For module/pam_userdb +AC_CHECK_HEADERS(ndbm.h db.h) +dnl I suspect the following two lines are a hack. +HAVE_NDBM_H=$ac_cv_header_ndbm_h +AC_SUBST(HAVE_NDBM_H) + +dnl For module/pam_lastlog +AC_CHECK_HEADERS(lastlog.h utmp.h utmpx.h) + +dnl This following rule should be made conditional upon HAVE_LIBCRYPT +dnl being found. + +dnl Look for cracklib dictionary +AC_MSG_CHECKING(path to cracklib dictionary) +DICT_DIR_CANDIDATES="/usr/lib /usr/share/dict /usr/share/lib \ + /usr/local/lib /usr/local/share/lib" +DICT_FILE_CANDIDATES="pw_dict cracklib_dict" +CRACKLIB_DICTPATH="" +for d in $DICT_DIR_CANDIDATES ; do + for f in $DICT_FILE_CANDIDATES ; do + if test -r $d/$f.hwm ; then + CRACKLIB_DICTPATH=$d/$f + break 2 + elif test -r $d/dict/$f.hwm ; then + CRACKLIB_DICTPATH=$d/dict/$f + break 2 + fi + done +done +if test -z "$CRACKLIB_DICTPATH" ; then + AC_MSG_RESULT(none found) +else + AC_MSG_RESULT($CRACKLIB_DICTPATH) +fi +AC_SUBST(CRACKLIB_DICTPATH) + +dnl Set FLAGS, linker options etc. depending on C compiler. +dnl gcc is tested and much preferred; others less so, if at all +dnl +dnl If compiling with gcc, linking is also supposed to be done with gcc; +dnl since we use linker-specific arguments, we may not gain anything by +dnl switching LD_L over, but I think we can use LD_D as-is. +dnl +dnl For the moment, gcc is enforced above at "CC=gcc". +dnl +dnl There is an issue over _POSIX_SOURCE _BSD_SOURCE and _GNU_SOURCE . +dnl The original "Linux-PAM" had blanket inclusion. But portability +dnl requires their default absence: if particular OSes require them, +dnl this should be done selectively. + +GCC_WARNINGS="-Wall -Wwrite-strings \ + -Wpointer-arith -Wcast-qual -Wcast-align \ + -Wstrict-prototypes -Wmissing-prototypes \ + -Wnested-externs -Winline -Wshadow" + +if test "$GCC" = yes; then + CC=gcc ; AC_SUBST(CC) +### May need per-OS attention +### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris. + case $OS in + linux) + OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic" + LD_D="gcc -shared -Xlinker -x" + WARNINGS="$GCC_WARNINGS" + PIC="-fPIC" + DYNTYPE=so + LD=ld + LD_L="$LD -x -shared" + RANLIB=ranlib + STRIP=strip + CC_STATIC="-Xlinker -export-dynamic" + ;; + sunos) + OS_CFLAGS="-ansi -pedantic" + LD_D="gcc -shared -Xlinker -x" + WARNINGS="$GCC_WARNINGS" + PIC="-fPIC" + DYNTYPE=so + LD=ld + LD_L="$LD -x -shared" + RANLIB=ranlib + STRIP=strip + CC_STATIC="-Xlinker -export-dynamic" + ;; + aix) + OS_CFLAGS="" + DYNTYPE=lo + LD=ld + LD_L=ld -bexpall -bM:SRE -bnoentry + LD_D="$LD_L" + RANLIB=ranlib + STRIP=strip + ;; + *) + OS_CFLAGS="" + ;; + esac +else +### +### Non-gcc needs attention on per-OS basis +### + case "$OS" in + darwin) +# add some stuff here (see sourceforge bug 534205) +# DOCDIR=/System/Documentation/Administration/Libraries/PAM +# MANDIR=/usr/share/man + ;; + solaris) + ### Support for Solaris-C + OS_CFLAGS="" + WARNINGS="" + PIC="-K pic" + LD=ld + LD_D="cc -z text -G -R." + LD_L="$LD_D" + RANLIB=ranlib + STRIP=strip + CC_STATIC= + ;; + irix*) + OSRELEASE=`uname -r` + if test "$OSRELEASE" = 6.5; then + OS_CFLAGS="" + WARNINGS="-fullwarn" + PIC= #PIC code is default for IRIX + LD="cc -shared" # modules friendly approach + LD_D="cc -shared" + LD_L="ld -G -z redlocsym" + RANLIB=echo + STRIP=strip + CC_STATIC= + else + echo "IRIX prior to 6.5 not allowed for" + exit + fi + ;; + *) echo "Native compiler on $OS is not yet supported" + exit + ;; + esac +fi + +AC_SUBST(DYNTYPE) +AC_SUBST(OS_CFLAGS) +AC_SUBST(WARNINGS) +AC_SUBST(PIC) +AC_SUBST(LD) +AC_SUBST(LD_D) +AC_SUBST(LD_L) +AC_SUBST(RANLIB) +AC_SUBST(STRIP) +AC_SUBST(CC_STATIC) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_BIGENDIAN +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_TYPE_GETGROUPS +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(gethostname gettimeofday mkdir select strcspn strdup strerror strspn strstr strtol uname) + +AC_CHECK_FUNCS(getpwnam_r getgrnam_r) + +dnl Checks for programs/utilities +AC_CHECK_PROG(HAVE_SGML2TXT, sgml2txt, yes, no) +AC_CHECK_PROG(HAVE_SGML2HTML, sgml2html, yes, no) +AC_CHECK_PROG(HAVE_SGML2LATEX, sgml2latex, yes, no) +if test $HAVE_SGML2LATEX = "yes" ; then + if sgml2latex -h | grep -e --paper | grep ' -p ' > /dev/null ; then + PSER="sgml2latex -o ps" + else + PSER="sgml2latex -p" + fi + AC_CHECK_PROG(HAVE_PS2PDF, ps2pdf, yes, no) +else + AC_CHECK_PROG(HAVE_SGML2PS, sgml2ps, yes, no) + if test $HAVE_SGML2PS = yes ; then + PSER="sgml2ps" + fi +fi +AC_SUBST(PSER) +AC_SUBST(PS2PDF) + +dnl Files to be created from when we run configure +AC_OUTPUT(Make.Rules) diff --git a/Linux-PAM/defs/debian.defs b/Linux-PAM/defs/debian.defs new file mode 100644 index 00000000..19ba4663 --- /dev/null +++ b/Linux-PAM/defs/debian.defs @@ -0,0 +1,40 @@ +## +# defs for Debian +# Ben Collins +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +## + +CFLAGS := -O2 -I${shell pwd}/include # -D__NO_STRING_INLINES +ifneq (,$(findstring $(DEB_BUILD_OPTIONS),debug DEBUG Debug)) + CFLAGS += -g +endif + +OS := $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM) +ARCH := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) +CC := gcc +INSTALL := install +MKDIR := mkdir -p +ULIBS := +LD := ld +LD_D := gcc -shared -Xlinker -x +LD_L := $(LD) -x -shared +AR := ar -cr +RANLIB := ranlib +PREFIX := +LIBDIR := $(PREFIX)/lib +USESONAME := yes +SOSWITCH := -soname +LINKLIBS := -lc -L${shell pwd}/libpam -L${shell pwd}/libpam_misc +NEEDSONAME := no +LDCONFIG := /sbin/ldconfig +FAKEROOT := +SUPLEMENTED := $(PREFIX)/sbin +SECUREDIR := $(LIBDIR)/security +INCLUDED := /usr/include/security +CONFIGED := /etc +SCONFIGED := /etc/security +EXTRALS := -lnsl -lcrypt +WARNINGS := -Wall diff --git a/Linux-PAM/defs/hpux.defs b/Linux-PAM/defs/hpux.defs new file mode 100644 index 00000000..d8341983 --- /dev/null +++ b/Linux-PAM/defs/hpux.defs @@ -0,0 +1,36 @@ +## +# HPUX defs contributed by Derrick J Brashear +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the default version. Please look in .../defs/ for your +# preferred OS/vendor. + +OS=hpux9 +ARCH=hpux +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=-g -DPAM_SHL -DHAVE_UTMP_H +ULIBS= +LD=ld +LD_D=$(LD) -b +LD_L=$(LD) -b +USESONAME=no +NEEDSONAME=no +LDCONFIG=: +AR=ar -cr +RANLIB=ranlib +FAKEROOT= +PREFIX=/usr +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security +DYNLOAD="dld" +DYNTYPE="sl" +SHLIBMODE=755 diff --git a/Linux-PAM/defs/linux.defs b/Linux-PAM/defs/linux.defs new file mode 100644 index 00000000..0e274320 --- /dev/null +++ b/Linux-PAM/defs/linux.defs @@ -0,0 +1,32 @@ +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the default version. Please look in .../defs/ for your +# preferred OS/vendor. + +OS=linux +ARCH=i386 # should be changed for alpha +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=-O7 -pipe -g +ULIBS=#-lefence +LD=ld +LD_D=gcc -shared -Xlinker -x +LD_L=$(LD) -x -shared +USESONAME=yes +LINKLIBS=-lc +SOSWITCH=-soname +NEEDSONAME=no +LDCONFIG=/sbin/ldconfig +AR=ar -cr +RANLIB=ranlib +FAKEROOT= +PREFIX=/usr +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security diff --git a/Linux-PAM/defs/morgan.defs b/Linux-PAM/defs/morgan.defs new file mode 100644 index 00000000..2b0cf289 --- /dev/null +++ b/Linux-PAM/defs/morgan.defs @@ -0,0 +1,36 @@ +## +# defs for Andrew's debugging version (which is a modified Red Hat +# box) +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the version used for Red Hat Linux. + +OS=linux +ARCH=i386 +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=$(RPM_OPT_FLAGS) -pipe -g +ULIBS= +#-lefence +LD=ld +LD_D=gcc -shared -Xlinker -x +LD_L=$(LD) -x -shared +USESONAME=yes +SOSWITCH=-soname +LINKLIBS=-lc +NEEDSONAME=no +LDCONFIG=/sbin/ldconfig +AR=ar -cr +RANLIB=ranlib +FAKEROOT=$(RPM_BUILD_ROOT) +PREFIX= +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security.d +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security diff --git a/Linux-PAM/defs/redhat.defs b/Linux-PAM/defs/redhat.defs new file mode 100644 index 00000000..a6ed36da --- /dev/null +++ b/Linux-PAM/defs/redhat.defs @@ -0,0 +1,36 @@ +## +# defs for Red Hat Linux +# Michael K. Johnson +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the version used for Red Hat Linux. + +OS=linux +ARCH=$(shell rpm --showrc | grep '^build arch' | sed 's/^.*: //g') +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=$(RPM_OPT_FLAGS) -pipe -g +ULIBS=#-lefence +LD=ld +LD_D=gcc -shared -Xlinker -x +LD_L=$(LD) -x -shared +USESONAME=yes +SOSWITCH=-soname +LINKLIBS=-lc +NEEDSONAME=no +LDCONFIG=/sbin/ldconfig +AR=ar -cr +RANLIB=ranlib +FAKEROOT=$(RPM_BUILD_ROOT) +PREFIX= +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security +EXTRALS=-lcrypt diff --git a/Linux-PAM/defs/redhat4.defs b/Linux-PAM/defs/redhat4.defs new file mode 100644 index 00000000..219abeb6 --- /dev/null +++ b/Linux-PAM/defs/redhat4.defs @@ -0,0 +1,35 @@ +## +# defs for Red Hat Linux +# Michael K. Johnson +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the version used for Red Hat Linux. + +OS=linux +ARCH=$(shell rpm --showrc | grep '^build arch' | sed 's/^.*: //g') +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=$(RPM_OPT_FLAGS) -pipe -g +ULIBS=#-lefence +LD=ld +LD_D=gcc -shared -Xlinker -x +LD_L=$(LD) -x -shared +USESONAME=yes +SOSWITCH=-soname +LINKLIBS=-lc +NEEDSONAME=no +LDCONFIG=/sbin/ldconfig +AR=ar -cr +RANLIB=ranlib +FAKEROOT=$(RPM_BUILD_ROOT) +PREFIX= +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security diff --git a/Linux-PAM/defs/solaris-2.1.5.defs b/Linux-PAM/defs/solaris-2.1.5.defs new file mode 100644 index 00000000..4624b604 --- /dev/null +++ b/Linux-PAM/defs/solaris-2.1.5.defs @@ -0,0 +1,45 @@ +## +# Solaris defs contributed by Josh Wilmes +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the default version. Please look in .../defs/ for your +# preferred OS/vendor. + +# Please note that the linker used must be the GNU ld, not the native Sun +# linker. It is fairly common for the gnu linker (/usr/ccs/bin/ld) to be +# configured as the default linker for gcc. To tell gcc to use the +# gnu linker, you need to set the GCC_EXEC_PREFIX environment variable +# to point at the directory where the gnu linker is installed. Here's +# what I do: +# $ mkdir /tmp/foo +# $ ln -s /path/to/gnu/ld /tmp/foo/ld +# $ export GCC_EXEC_PREFIX=/tmp/foo/ +# $ export PATH=/tmp/foo:$PATH + +OS=solaris +ARCH=sun +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=-O7 -pipe -g -D__EXTENSIONS__ -Dsolaris +ULIBS= +LD_D=gcc -shared -Xlinker -x +LD=ld +LD_L=$(LD) -G +USESONAME=yes +SOSWITCH=-h +NEEDSONAME=no +LDCONFIG=/sbin/echo +AR=ar -cr +RANLIB=ranlib +FAKEROOT= +PREFIX=/usr +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security diff --git a/Linux-PAM/defs/solaris.defs b/Linux-PAM/defs/solaris.defs new file mode 100644 index 00000000..f9f26529 --- /dev/null +++ b/Linux-PAM/defs/solaris.defs @@ -0,0 +1,48 @@ +## +# Solaris defs contributed by Josh Wilmes +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the default version. Please look in .../defs/ for your +# preferred OS/vendor. + +# Please note that the linker used must be the GNU ld, not the native Sun +# linker. It is fairly common for the gnu linker (/usr/ccs/bin/ld) to be +# configured as the default linker for gcc. To tell gcc to use the +# gnu linker, you need to set the GCC_EXEC_PREFIX environment variable +# to point at the directory where the gnu linker is installed. Here's +# what I do: +# $ mkdir /tmp/foo +# $ ln -s /path/to/gnu/ld /tmp/foo/ld +# $ export GCC_EXEC_PREFIX=/tmp/foo/ +# $ export PATH=/tmp/foo:$PATH + +OS=solaris +ARCH=sun +CC=cc +INSTALL=install +MKDIR=mkdir -p +WARNINGS = -D_POSIX_SOURCE +PIC=-KPIC +CFLAGS=-g -D__EXTENSIONS__ -Dsolaris +ULIBS= +LD=ld +LD_L=$(LD) -G +LD_D=$(LD_L) +RDYNAMIC= +USESONAME=yes +SOSWITCH=-h +NEEDSONAME=no +LDCONFIG=echo +AR=ar -cr +RANLIB=ranlib +FAKEROOT= +PREFIX=/usr +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security diff --git a/Linux-PAM/defs/sunos.defs b/Linux-PAM/defs/sunos.defs new file mode 100644 index 00000000..158accc5 --- /dev/null +++ b/Linux-PAM/defs/sunos.defs @@ -0,0 +1,37 @@ +## +# SunOS defs contributed by Derrick J Brashear +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the SunOS version. Please look in .../defs/ for your +# preferred OS/vendor. + +OS=sunos +ARCH=sun +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=-O2 -pipe -g -D__EXTENSIONS__ +ULIBS= +LD_D=gcc -shared -Xlinker -x +LD=ld +LD_L=$(LD) +USESONAME=no +NEEDSONAME=yes +LDCONFIG=/usr/etc/ldconfig +AR=ar cr +RANLIB=ranlib +FAKEROOT= +PREFIX=/usr +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security +WARNINGS= -ansi -Wall -Wwrite-strings \ + -Wpointer-arith -Wcast-qual -Wcast-align \ + -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \ + -Wnested-externs -Winline -Wshadow diff --git a/Linux-PAM/defs/suse.defs b/Linux-PAM/defs/suse.defs new file mode 100644 index 00000000..1fc6b741 --- /dev/null +++ b/Linux-PAM/defs/suse.defs @@ -0,0 +1,36 @@ +## +# defs for SuSE Linux +# Thorsten Kukuk +## +# this file indicates the compiler and the various hardware/OS dependent +# flags for installation. It also defines the various destinations of +# installed files on the system. +# +# This file is the version used for SuSE Linux. + +OS=linux +ARCH=$(shell rpm --showrc | grep 'build arch' | grep -v "compatible" | sed 's/^.*: //g') +CC=gcc +INSTALL=install +MKDIR=mkdir -p +CFLAGS=$(RPM_OPT_FLAGS) -pipe -D_REENTRANT +ULIBS=#-lefence +LD=ld +LD_D=gcc -shared -Xlinker -x +LD_L=$(LD) -x -shared +USESONAME=yes +SOSWITCH=-soname +LINKLIBS=-lc +NEEDSONAME=yes +LDCONFIG=/sbin/ldconfig +AR=ar -cr +RANLIB=ranlib +FAKEROOT=$(RPM_BUILD_ROOT) +PREFIX= +SUPLEMENTED=$(PREFIX)/sbin +LIBDIR=$(PREFIX)/lib +SECUREDIR=$(LIBDIR)/security +INCLUDED=/usr/include/security +CONFIGED=/etc +SCONFIGED=/etc/security +EXTRALS=-lcrypt diff --git a/Linux-PAM/doc/CREDITS b/Linux-PAM/doc/CREDITS new file mode 100644 index 00000000..1b40f7fd --- /dev/null +++ b/Linux-PAM/doc/CREDITS @@ -0,0 +1,49 @@ + +Chris Adams, +Peter Allgeyer, +Tim Baverstock, +Tim Berger, +Craig S. Bell, +Derrick J. Brashear, +Ben Buxton, +Seth Chaiklin, +Oliver Crow, +Chris Dent, +Marc Ewing, +Cristian Gafton, +Emmanuel Galanos, +Brad M. Garcia, +Eric Hester, +Michel D'Hooge, +Roger Hu, +Eric Jacksch, +Michael K. Johnson, +David Kinchlea, +Olaf Kirch, +Marcin Korzonek, +Stephen Langasek, +Nicolai Langfeldt, +Elliot Lee, +Luke Kenneth Casson Leighton, +Al Longyear, +Ingo Luetkebohle, +Marek Michalkiewicz, +Robert Milkowski, +Aleph One, +Martin Pool, +Sean Reifschneider, +Jan Rekorajski, +Erik Troan, +Theodore Ts'o, +Jeff Uphoff, +Myles Uyema, +Savochkin Andrey Vladimirovich, +Ronald Wahl, +David Wood, +John Wilmes, +Joseph S. D. Yao +and +Alex O. Yuriev. diff --git a/Linux-PAM/doc/Makefile b/Linux-PAM/doc/Makefile new file mode 100644 index 00000000..20c2a23f --- /dev/null +++ b/Linux-PAM/doc/Makefile @@ -0,0 +1,167 @@ + +### $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:24 hartmans Exp $ + +include ../Make.Rules + +####################################################### + +FILES=pam pam_appl pam_modules +FSRCS=pam.sgml pam_appl.sgml pam_modules.sgml + +TEXTS=txts/pam.txt txts/pam_appl.txt txts/pam_modules.txt +HTMLS=html/pam.html html/pam_appl.html html/pam_modules.html +PSFILES=ps/pam.ps ps/pam_appl.ps ps/pam_modules.ps +PDFFILES=pdf/pam.pdf ps/pam_appl.pdf ps/pam_modules.pdf + +MODULES=$(shell ls modules/*.sgml) + +####################################################### + +dummy: + @echo "Making the documentation..." + @$(MAKE) all + +# note, at this time we don't include pdf files by default, but you +# can type make pdf in this directory and see what happens in the pdf +# subdirectory. + +all: htmls texts postscript + +htmls: $(HTMLS) + +$(HTMLS) : $(FSRCS) +ifeq ($(HAVE_SGML2HTML),yes) + @for i in $(FILES) ; do \ + if [ ! -f "html/$$i.html" ] || [ "$$i.sgml" -nt "html/$$i.html" ]; \ + then \ + cd html ; sgml2html ../$$i ; \ + if [ $$? -ne 0 ]; then exit 1 ; fi ; \ + cd .. ; \ + fi ; \ + done +else + @echo XXX - you do not have the sgml2html binary installed +endif + +texts: $(TEXTS) + +$(TEXTS) : $(FSRCS) +ifeq ($(HAVE_SGML2TXT),yes) + @for i in $(FILES) ; do \ + if [ ! -f "txts/$$i.txt" ] \ + || [ "$$i.sgml" -nt "txts/$$i.txt" ]; then \ + cd txts ; sgml2txt ../$$i ; cd .. ; \ + fi ; \ + done +else + @echo XXX - you do not have the sgml2txt binary installed +endif + +postscript: $(PSFILES) + +$(PSFILES): $(FSRCS) +ifneq ($(PSER),) + @for i in $(FILES) ; do \ + if [ ! -f "ps/$$i.ps" ] || [ "$$i.sgml" -nt "ps/$$i.ps" ]; then \ + cd ps ; $(PSER) ../$$i ; cd .. ; \ + fi ; \ + done +else + @echo XXX - neither sgml2ps nor sgml2latex binaries are installed +endif + +pdf: $(PDFFILES) + +$(PDFFILES) : $(PSFILES) +ifeq ($(HAVE_PS2PDF),yes) + @for i in $(FILES) ; do \ + if [ ! -f "pdf/$$i.pdf" ] || [ "ps/$$i.ps" -nt "ps/$$i.pdf" ]; then \ + ps2pdf ps/$$i.ps pdf/$$i.pdf ; \ + fi ; \ + done +else + @echo XXX - ps2pdf is not installed +endif + +pam.sgml: pam_source.sgml MODULES-SGML CREDITS + @sed -e '/^/r MODULES-SGML' pam_source.sgml | sed -e '/^/r CREDITS' > pam.sgml + +MODULES-SGML: $(MODULES) + @echo 'Building module text from files in modules/*.sgml' + @rm -f MODULES-SGML + @echo '' >> MODULES-SGML + @cat modules/*.sgml >> MODULES-SGML + +extraclean: clean + +remove: + cd man && for file in *.3 ; do \ + rm -f $(FAKEROOT)$(MANDIR)/man3/$$file ; \ + done + cd man && for file in *.8 ; do \ + rm -f $(FAKEROOT)$(MANDIR)/man8/$$file ; \ + done + cd txts && for file in *.txt; do \ + rm -f $(FAKEROOT)$(DOCDIR)/text/$$file ; \ + done + cd ps && for file in *.ps; do \ + rm -f $(FAKEROOT)$(DOCDIR)/ps/$$file ; \ + done + cd html && for file in *.html; do \ + rm -f $(FAKEROOT)$(DOCDIR)/html/$$file ; \ + done + +install: all +ifeq ($(HAVE_SGML2TXT),yes) + mkdir -p $(FAKEROOT)$(DOCDIR)/text + for file in txts/*.txt; do \ + install -m 644 $$file $(FAKEROOT)$(DOCDIR)/text ; \ + done +endif +ifneq ($(PSER),) + mkdir -p $(FAKEROOT)$(DOCDIR)/ps + for file in ps/*.ps; do \ + install -m 644 $$file $(FAKEROOT)$(DOCDIR)/ps ; \ + done + ifeq ($(HAVE_PS2PDF),yes) + mkdir -p $(FAKEROOT)$(DOCDIR)/pdf + for file in pdf/*.pdf; do \ + install -m 644 $$file $(FAKEROOT)$(DOCDIR)/pdf ; \ + done + endif +endif +ifeq ($(HAVE_SGML2HTML),yes) + mkdir -p $(FAKEROOT)$(DOCDIR)/html + for file in html/*.html; do \ + install -m 644 $$file $(FAKEROOT)$(DOCDIR)/html ; \ + done +endif + mkdir -p $(FAKEROOT)$(MANDIR)/man3 + mkdir -p $(FAKEROOT)$(MANDIR)/man8 + for file in man/*.3 ; do \ + install -m 644 $$file $(FAKEROOT)$(MANDIR)/man3 ; \ + done + for file in man/*.8 ; do \ + install -m 644 $$file $(FAKEROOT)$(MANDIR)/man8 ; \ + done + +spec: specs/draft-morgan-pam.raw + cd specs/formatter && $(MAKE) + specs/formatter/padout < specs/draft-morgan-pam.raw > specs/draft-morgan-pam-current.txt + +releasedocs: all spec + tar zvfc Linux-PAM-$(MAJOR_REL).$(MINOR_REL)-docs.tar.gz --exclude CVS html ps txts specs/draft-morgan-pam-current.txt + +clean: + rm -f *~ *.bak + rm -f html/pam*.html + rm -f man/*~ + rm -f $(TEXTS) + rm -f $(PSFILES) ps/missfont.log + rm -f pdf/*.pdf + rm -f MODULES-SGML pam.sgml + rm -f specs/draft-morgan-pam-current.txt + $(MAKE) -C specs/formatter clean + diff --git a/Linux-PAM/doc/NOTES b/Linux-PAM/doc/NOTES new file mode 100644 index 00000000..b0f40d47 --- /dev/null +++ b/Linux-PAM/doc/NOTES @@ -0,0 +1,16 @@ +Things to be added: + +@ modules: +@ application: + + use of + 'user' = user to become, + 'uid' = user requesting service + 'euid' = privilege of current process. + +@ sysadmin: + + included modules: + behavior + non-included modules: + behavior/pointers. diff --git a/Linux-PAM/doc/figs/pam_orient.txt b/Linux-PAM/doc/figs/pam_orient.txt new file mode 100644 index 00000000..a8b745a1 --- /dev/null +++ b/Linux-PAM/doc/figs/pam_orient.txt @@ -0,0 +1,23 @@ + + + + +----------------+ + | application: X | + +----------------+ / +----------+ +================+ + | authentication-[---->--\--] Linux- |--<--| /etc/pam.conf | + | + [----<--/--] PAM | |================| + |[conversation()][--+ \ | | | X auth .. a.so | + +----------------+ | / +-n--n-----+ | X auth .. b.so | + | | | __| | | _____/ + | service user | A | | |____,-----' + | | | V A + +----------------+ +------|-----|---------+ -----+------+ + +---u-----u----+ | | | + | auth.... |--[ a ]--[ b ]--[ c ] + +--------------+ + | acct.... |--[ b ]--[ d ] + +--------------+ + | password |--[ b ]--[ c ] + +--------------+ + | session |--[ e ]--[ c ] + +--------------+ \ No newline at end of file diff --git a/Linux-PAM/doc/html/index.html b/Linux-PAM/doc/html/index.html new file mode 100644 index 00000000..8ab3b9ec --- /dev/null +++ b/Linux-PAM/doc/html/index.html @@ -0,0 +1,21 @@ + + + +Linux-PAM - Pluggable Authentication Modules for Linux + + + +

+Here is the documentation for Linux-PAM. As you will see it is +currently not complete. However, in order of decreasing length: + +

+ +
+

+REVISION: $Id: index.html,v 1.1.1.1 2001/04/29 04:16:52 hartmans Exp $ + diff --git a/Linux-PAM/doc/man/pam.8 b/Linux-PAM/doc/man/pam.8 new file mode 100644 index 00000000..f2ef9c1f --- /dev/null +++ b/Linux-PAM/doc/man/pam.8 @@ -0,0 +1,369 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam.8,v 1.1.1.1 2001/04/29 04:16:52 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996-7,2001 +.TH PAM 8 "2001 Jan 20" "Linux-PAM 0.74" "Linux-PAM Manual" +.SH NAME + +Linux-PAM \- Pluggable Authentication Modules for Linux + +.SH SYNOPSIS +.B /etc/pam.conf +.sp 2 +.SH DESCRIPTION + +This manual is intended to offer a quick introduction to +.BR Linux-PAM ". " +For more information the reader is directed to the +.BR "Linux-PAM system administrators' guide". + +.sp +.BR Linux-PAM +Is a system of libraries that handle the authentication tasks of +applications (services) on the system. The library provides a stable +general interface (Application Programming Interface - API) that +privilege granting programs (such as +.BR login "(1) " +and +.BR su "(1)) " +defer to to perform standard authentication tasks. + +.sp +The principal feature of the PAM approach is that the nature of the +authentication is dynamically configurable. In other words, the +system administrator is free to choose how individual +service-providing applications will authenticate users. This dynamic +configuration is set by the contents of the single +.BR Linux-PAM +configuration file +.BR /etc/pam.conf "." +Alternatively, the configuration can be set by individual +configuration files located in the +.B /etc/pam.d/ +directory. +.IB "The presence of this directory will cause " Linux-PAM " to ignore" +.BI /etc/pam.conf "." + +.sp +From the point of view of the system administrator, for whom this +manual is provided, it is not of primary importance to understand the +internal behavior of the +.BR Linux-PAM +library. The important point to recognize is that the configuration +file(s) +.I define +the connection between applications +.BR "" "(" services ")" +and the pluggable authentication modules +.BR "" "(" PAM "s)" +that perform the actual authentication tasks. + +.sp +.BR Linux-PAM +separates the tasks of +.I authentication +into four independent management groups: +.BR "account" " management; " +.BR "auth" "entication management; " +.BR "password" " management; " +and +.BR "session" " management." +(We highlight the abbreviations used for these groups in the +configuration file.) + +.sp +Simply put, these groups take care of different aspects of a typical +user's request for a restricted service: + +.sp +.BR account " - " +provide account verification types of service: has the user's password +expired?; is this user permitted access to the requested service? + +.br +.BR auth "entication - " +establish the user is who they claim to be. Typically this is via some +challenge-response request that the user must satisfy: if you are who +you claim to be please enter your password. Not all authentications +are of this type, there exist hardware based authentication schemes +(such as the use of smart-cards and biometric devices), with suitable +modules, these may be substituted seamlessly for more standard +approaches to authentication - such is the flexibility of +.BR Linux-PAM "." + +.br +.BR password " - " +this group's responsibility is the task of updating authentication +mechanisms. Typically, such services are strongly coupled to those of +the +.BR auth +group. Some authentication mechanisms lend themselves well to being +updated with such a function. Standard UN*X password-based access is +the obvious example: please enter a replacement password. + +.br +.BR session " - " +this group of tasks cover things that should be done prior to a +service being given and after it is withdrawn. Such tasks include the +maintenance of audit trails and the mounting of the user's home +directory. The +.BR session +management group is important as it provides both an opening and +closing hook for modules to affect the services available to a user. + +.SH The configuration file(s) + +When a +.BR Linux-PAM +aware privilege granting application is started, it activates its +attachment to the PAM-API. This activation performs a number of +tasks, the most important being the reading of the configuration file(s): +.BR /etc/pam.conf "." +Alternatively, this may be the contents of the +.BR /etc/pam.d/ +directory. + +These files list the +.BR PAM "s" +that will do the authentication tasks required by this service, and +the appropriate behavior of the PAM-API in the event that individual +.BR PAM "s " +fail. + +.sp +The syntax of the +.B /etc/pam.conf +configuration file is as follows. The file is made +up of a list of rules, each rule is typically placed on a single line, +but may be extended with an escaped end of line: `\\'. Comments +are preceded with `#' marks and extend to the next end of line. + +.sp +The format of each rule is a space separated collection of tokens, the +first three being case-insensitive: + +.sp +.br +.BR " service type control module-path module-arguments" + +.sp +The syntax of files contained in the +.B /etc/pam.d/ +directory, are identical except for the absence of any +.I service +field. In this case, the +.I service +is the name of the file in the +.B /etc/pam.d/ +directory. This filename must be in lower case. + +.sp +An important feature of +.BR Linux-PAM ", " +is that a number of rules may be +.I stacked +to combine the services of a number of PAMs for a given authentication +task. + +.sp +The +.BR service +is typically the familiar name of the corresponding application: +.BR login +and +.BR su +are good examples. The +.BR service "-name, " other ", " +is reserved for giving +.I default +rules. Only lines that mention the current service (or in the absence +of such, the +.BR other +entries) will be associated with the given service-application. + +.sp +The +.BR type +is the management group that the rule corresponds to. It is used to +specify which of the management groups the subsequent module is to +be associated with. Valid entries are: +.BR account "; " +.BR auth "; " +.BR password "; " +and +.BR session "." +The meaning of each of these tokens was explained above. + +.sp +The third field, +.BR control ", " +indicates the behavior of the PAM-API should the module fail to +succeed in its authentication task. There are two types of syntax for +this control field: the simple one has a single simple keyword; the +more complicated one involves a square-bracketed selection of +.B value=action +pairs. + +.sp +For the simple (historical) syntax valid +.BR control +values are: +.BR requisite +- failure of such a PAM results in the immediate termination of the +authentication process; +.BR required +- failure of such a PAM will ultimately lead to the PAM-API returning +failure but only after the remaining +.I stacked +modules (for this +.BR service +and +.BR type ")" +have been invoked; +.BR sufficient +- success of such a module is enough to satisfy the authentication +requirements of the stack of modules (if a prior +.BR required +module has failed the success of this one is +.IR ignored "); " +.BR optional +- the success or failure of this module is only important if it is the +only module in the stack associated with this +.BR service "+" type "." + +.sp +For the more complicated syntax valid +.B control +values have the following form: +.sp +.RB [value1=action1 value2=action2 ...] +.sp +Where +.B valueN +corresponds to the return code from the function invoked in the module +for which the line is defined. It is selected from one of these: +.BR success ; +.BR open_err ; +.BR symbol_err ; +.BR service_err ; +.BR system_err ; +.BR buf_err ; +.BR perm_denied ; +.BR auth_err ; +.BR cred_insufficient ; +.BR authinfo_unavail ; +.BR user_unknown ; +.BR maxtries ; +.BR new_authtok_reqd ; +.BR acct_expired ; +.BR session_err ; +.BR cred_unavail ; +.BR cred_expired ; +.BR cred_err ; +.BR no_module_data ; +.BR conv_err ; +.BR authtok_err ; +.BR authtok_recover_err ; +.BR authtok_lock_busy ; +.BR authtok_disable_aging ; +.BR try_again ; +.BR ignore ; +.BR abort ; +.BR authtok_expired ; +.BR module_unknown ; +.BR bad_item "; and" +.BR default . +The last of these, +.BR default , +implies 'all +.BR valueN 's +not mentioned explicitly. Note, the full list of PAM errors is +available in /usr/include/security/_pam_types.h . The +.B actionN +can be: an unsigned integer, +.BR J , +signifying an action of 'jump over the next J modules in the stack'; +or take one of the following forms: +.br +.B ignore +- when used with a stack of modules, the module's return status will +not contribute to the return code the application obtains; +.br +.B bad +- this action indicates that the return code should be thought of as +indicative of the module failing. If this module is the first in the +stack to fail, its status value will be used for that of the whole +stack. +.br +.B die +- equivalent to bad with the side effect of terminating the module +stack and PAM immediately returning to the application. +.br +.B ok +- this tells PAM that the administrator thinks this return code +should contribute directly to the return code of the full stack of +modules. In other words, if the former state of the stack would lead +to a return of +.BR PAM_SUCCESS , +the module's return code will override this value. Note, if the former +state of the stack holds some value that is indicative of a modules +failure, this 'ok' value will not be used to override that value. +.br +.B done +- equivalent to ok with the side effect of terminating the module +stack and PAM immediately returning to the application. +.br +.B reset +- clear all memory of the state of the module stack and start again +with the next stacked module. + +.sp +.BR module-path +- this is either the full filename of the PAM to be used by the +application (it begins with a '/'), or a relative pathname from the +default module location: +.BR /lib/security/ . + +.sp +.BR module-arguments +- these are a space separated list of tokens that can be used to +modify the specific behavior of the given PAM. Such arguments will be +documented for each individual module. + +.SH "FILES" +.BR /etc/pam.conf " - the configuration file" +.br +.BR /etc/pam.d/ " - the" +.BR Linux-PAM +configuration directory. Generally, if this directory is present, the +.B /etc/pam.conf +file is ignored. +.br +.BR /lib/libpam.so.X " - the dynamic library" +.br +.BR /lib/security/*.so " - the PAMs + +.SH ERRORS +Typically errors generated by the +.BR Linux-PAM +system of libraries, will be written to +.BR syslog "(3)." + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. +.br +Contains additional features, but remains backwardly compatible with +this RFC. + +.SH BUGS +.sp 2 +None known. + +.SH "SEE ALSO" + +The three +.BR Linux-PAM +Guides, for +.BR "system administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam.conf.8 b/Linux-PAM/doc/man/pam.conf.8 new file mode 100644 index 00000000..d067b559 --- /dev/null +++ b/Linux-PAM/doc/man/pam.conf.8 @@ -0,0 +1 @@ +.so pam.8 diff --git a/Linux-PAM/doc/man/pam.d.8 b/Linux-PAM/doc/man/pam.d.8 new file mode 100644 index 00000000..d067b559 --- /dev/null +++ b/Linux-PAM/doc/man/pam.d.8 @@ -0,0 +1 @@ +.so pam.8 diff --git a/Linux-PAM/doc/man/pam_authenticate.3 b/Linux-PAM/doc/man/pam_authenticate.3 new file mode 100644 index 00000000..bc1cd5c9 --- /dev/null +++ b/Linux-PAM/doc/man/pam_authenticate.3 @@ -0,0 +1,91 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_authenticate.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996-7 +.TH PAM_AUTHENTICATE 3 "1996 Dec 9" "Linux-PAM 0.55" "App. Programmers' Manual" +.SH NAME + +pam_authenticate \- authenticate a user + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_authenticate(pam_handle_t " *pamh ", int " flags ");" +.sp 2 +.SH DESCRIPTION +.B pam_authenticate + +.br +Use this function to authenticate an applicant user. It is linked +.I dynamically +to the authentication modules by +.BR Linux-PAM ". " +It is the task of these module to perform such an authentication. The +specific nature of the authentication is not the concern of the +application. + +.br +Following successful completion, the +.BR name +of the authenticated user will be present in the +.BR Linux-PAM +item +.BR PAM_USER ". " +This item may be recovered with a call to +.BR pam_get_item "(3)." + +.br +The application developer should note that the modules may request +that the user enter their username via the conversation mechanism (see +.BR pam_start "(3))." +Should this be the case, the user-prompt string can be set via +the +.BR PAM_USER_PROMPT +item (see +.BR pam_set_item "(3))." + +.SH "RETURN VALUE" +On success +.BR PAM_SUCCESS +is returned. All other returns should be considered +authentication failures and will be +.I delayed +by an amount specified with prior calls to +.BR pam_fail_delay "(3). " +Specific failures that demand special attention are the following: +.TP +.B PAM_ABORT +the application should exit immediately. Of course, +.BR pam_end "(3)" +should be called first. + +.TP +.B PAM_MAXTRIES +the application has tried too many times to authenticate the +user, authentication should not be attempted again. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_start "(3), " +.BR pam_get_item "(3) " +.BR pam_fail_delay "(3) " +and +.BR pam_strerror "(3). " + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_chauthtok.3 b/Linux-PAM/doc/man/pam_chauthtok.3 new file mode 100644 index 00000000..94a8f2d3 --- /dev/null +++ b/Linux-PAM/doc/man/pam_chauthtok.3 @@ -0,0 +1,101 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_chauthtok.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1997 +.TH PAM_CHAUTHTOK 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual" +.SH NAME + +pam_chauthtok \- updating authentication tokens + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_chauthtok(pam_handle_t " *pamh ", int " flags ");" +.sp 2 +.SH DESCRIPTION +.B pam_chauthtok + +.br +Use this function to rejuvenate the authentication tokens (passwords +etc.) of an applicant user. + +.br +Note, the application should not pre-authenticate the user, as this is +performed (if required) by the +.BR Linux-PAM +framework. + +.br +The +.I flags +argument can +.I optionally +take the value, +.BR PAM_CHANGE_EXPIRED_AUTHTOK "." +In such cases the framework is only required to update those +authentication tokens that have expired. Without this argument, the +framework will attempt to obtain new tokens for all configured +authentication mechanisms. The details of the types and number of such +schemes should not concern the calling application. + +.SH RETURN VALUE +A successful return from this function will be indicated with +.BR PAM_SUCCESS "." + +.br +Specific errors of special interest when calling this function are + +.br +.BR PAM_AUTHTOK_ERROR +- a valid new token was not obtained + +.br +.BR PAM_AUTHTOK_RECOVERY_ERR +- old authentication token was not available + +.br +.BR PAM_AUTHTOK_LOCK_BUSY +- a resource needed to update the token was locked (try again later) + +.br +.BR PAM_AUTHTOK_DISABLE_AGING +- one or more of the authentication modules does not honor +authentication token aging + +.br +.BR PAM_TRY_AGAIN +- one or more authentication mechanism is not prepared to update a +token at this time + +.br +In general other return values may be returned. They should be treated +as indicating failure. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_start "(3), " +.BR pam_authenticate "(3), " +.BR pam_setcred "(3), " +.BR pam_get_item "(3), " +.BR pam_strerror "(3) " +and +.BR pam "(8)." + +.br +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_close_session.3 b/Linux-PAM/doc/man/pam_close_session.3 new file mode 100644 index 00000000..d851700c --- /dev/null +++ b/Linux-PAM/doc/man/pam_close_session.3 @@ -0,0 +1 @@ +.so pam_open_session.3 diff --git a/Linux-PAM/doc/man/pam_end.3 b/Linux-PAM/doc/man/pam_end.3 new file mode 100644 index 00000000..de999f24 --- /dev/null +++ b/Linux-PAM/doc/man/pam_end.3 @@ -0,0 +1 @@ +.so pam_start.3 diff --git a/Linux-PAM/doc/man/pam_fail_delay.3 b/Linux-PAM/doc/man/pam_fail_delay.3 new file mode 100644 index 00000000..63cc88b3 --- /dev/null +++ b/Linux-PAM/doc/man/pam_fail_delay.3 @@ -0,0 +1,130 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_fail_delay.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1997 +.TH PAM_FAIL_DELAY 3 "1997 Jan 12" "Linux-PAM 0.56" "Programmers' Manual" +.SH NAME + +pam_fail_delay \- request a delay on failure + +.SH SYNOPSIS +.B #include +.br +or, +.br +.B #include +.sp +.BI "int pam_fail_delay(pam_handle_t " "*pamh" ", unsigned int " "usec" ");" +.sp 2 +.SH DESCRIPTION +.br +It is often possible to attack an authentication scheme by exploiting +the time it takes the scheme to deny access to an applicant user. In +cases of +.I short +timeouts, it may prove possible to attempt a +.I brute force +dictionary attack -- with an automated process, the attacker tries all +possible passwords to gain access to the system. In other cases, +where individual failures can take measurable amounts of time +(indicating the nature of the failure), an attacker can obtain useful +information about the authentication process. These latter attacks +make use of procedural delays that constitute a +.I covert channel +of useful information. + +.br +To minimize the effectiveness of such attacks, it is desirable to +introduce a random delay in a failed authentication process. +.B Linux-PAM +provides such a facility. The delay occurs upon failure of the +.BR pam_authenticate "(3) " +and +.BR pam_chauthtok "(3) " +functions. It occurs +.I after +all authentication modules have been called, but +.I before +control is returned to the service application. + +.br +The function, +.BR pam_fail_delay "(3)," +is used to specify a required minimum for the length of the +failure-delay; the +.I usec +argument. This function can be called by the service application +and/or the authentication modules, both may have an interest in +delaying a reapplication for service by the user. The length of the +delay is computed at the time it is required. Its length is +pseudo-gausianly distributed about the +.I maximum +requested value; the resultant delay will differ by as much as 25% of +this maximum requested value (both up and down). + +.br +On return from +.BR pam_authenticate "(3) or " pam_chauthtok "(3)," +independent of success or failure, the new requested delay is reset to +its default value: zero. + +.SH EXAMPLE +.br +For example, a +.B login +application may require a failure delay of roughly 3 seconds. It will +contain the following code: +.sp +.br +.B " pam_fail_delay(pamh, 3000000 /* micro-seconds */ );" +.br +.B " pam_authenticate(pamh, 0);" +.sp +.br +if the modules do not request a delay, the failure delay will be +between 2.25 and 3.75 seconds. + +.br +However, the modules, invoked in the authentication process, may +also request delays: +.sp +.br +.RB " (module #1) " "pam_fail_delay(pamh, 2000000);" +.sp +.br +.RB " (module #2) " "pam_fail_delay(pamh, 4000000);" +.sp +.br +in this case, it is the largest requested value that is used to +compute the actual failed delay: here between 3 and 5 seconds. + +.SH "RETURN VALUE" +Following a successful call to +.BR pam_fail_delay "(3), " PAM_SUCCESS +is returned. All other returns should be considered serious failures. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +Under consideration by the X/Open group for future inclusion in the +PAM RFC. 1996/1/10 + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_start "(3), " +.BR pam_get_item "(3) " +and +.BR pam_strerror "(3). " + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_get_item.3 b/Linux-PAM/doc/man/pam_get_item.3 new file mode 100644 index 00000000..f4f0d462 --- /dev/null +++ b/Linux-PAM/doc/man/pam_get_item.3 @@ -0,0 +1 @@ +.so pam_set_item.3 diff --git a/Linux-PAM/doc/man/pam_open_session.3 b/Linux-PAM/doc/man/pam_open_session.3 new file mode 100644 index 00000000..05ccbb88 --- /dev/null +++ b/Linux-PAM/doc/man/pam_open_session.3 @@ -0,0 +1,99 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_open_session.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1997 +.TH PAM_OPEN_SESSION 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual" +.SH NAME + +pam_open/close_session \- PAM session management + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_open_session(pam_handle_t " *pamh ", int " flags ");" +.sp +.BI "int pam_close_session(pam_handle_t " *pamh ", int " flags ");" +.sp 2 +.SH DESCRIPTION + +PAM provides management-hooks for the initialization and termination +of a session. + +.TP +.B pam_open_session +.br +Use this function to signal that an authenticated user session has +begun. It should be called only after the user is properly identified +and (where necessary) has been granted their credentials with +.BR pam_authenticate "(3)" +and +.BR pam_setcred "(3)" +respectively. + +.br +Some types of functions associated with session +initialization are logging for the purposes of system-audit and +mounting directories (the user's home directory for example). These +should not concern the application. It should be noted that the +.I effective +uid, +.BR geteuid "(2)," +of the application should be of sufficient privilege to perform such +tasks. + +.TP +.B pam_close_session +.br +Use this function to signal that a user session has +terminated. In general this function may not need to be located in the +same application as the initialization function, +.BR pam_open_session "." + +.br +Typically, this function will undo the actions of +.BR pam_open_session "." +That is, log audit information concerning the end of the user session +or unmount the user's home directory. Apart from having sufficient +privilege the details of the session termination should not concern +the calling application. It is good programming practice, however, to +cease acting on behalf of the user on returning from this call. + +.SH RETURN VALUE +A successful return from the session management functions will be +indicated with +.BR PAM_SUCCESS "." + +.br +The specific error indicating a failure to open or close a session is +.BR PAM_SESSION_ERR "." +In general other return values may be returned. They should be treated +as indicating failure. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +OSF-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_start "(3), " +.BR pam_authenticate "(3), " +.BR pam_setcred "(3), " +.BR pam_get_item "(3), " +.BR pam_strerror "(3) " +and +.BR pam "(3)." + +.br +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_set_item.3 b/Linux-PAM/doc/man/pam_set_item.3 new file mode 100644 index 00000000..ad759cfd --- /dev/null +++ b/Linux-PAM/doc/man/pam_set_item.3 @@ -0,0 +1,55 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_set_item.3,v 1.1.1.1 2002/09/15 20:08:27 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996,1997 +.TH PAM_SET_ITEM 3 "2001 Jan 21" "Linux-PAM" "App. Programmers' Manual" +.SH NAME + +pam_set_item, pam_get_item \- item manipulation under PAM + +.SH SYNOPSIS +.B #include +.br +or +.br +.B #include +.sp +.BI "int pam_set_item(pam_handle_t " *pamh ", int " item_type ", void " *item ");" +.sp +.BI "int pam_get_item(const pam_handle_t " *pamh ", int " item_type ", const void " **item_p ");" +.sp 2 +.SH DESCRIPTION +.B pam_set_item +.sp +.B pam_set_item + +These functions are currently undocumented in a man page, but see the +end of this man page for more information (the PAM guides). + +On success +.BR PAM_SUCCESS +is returned, all other return values should be treated as errors. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam (8) +and +.BR pam_strerror "(3)." + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_setcred.3 b/Linux-PAM/doc/man/pam_setcred.3 new file mode 100644 index 00000000..9681690c --- /dev/null +++ b/Linux-PAM/doc/man/pam_setcred.3 @@ -0,0 +1,79 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_setcred.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996,1997 +.TH PAM_SETCRED 3 "1997 July 6" "Linux-PAM 0.58" "App. Programmers' Manual" +.SH NAME + +pam_setcred \- set the credentials for the user + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_setcred(pam_handle_t " *pamh ", int " flags ");" +.sp 2 +.SH DESCRIPTION +.B pam_setcred + +This function is used to establish, maintain and delete the +credentials of a user. It should be called after a user has been +authenticated and before a session is opened for the user (with +.BR pam_open_session "(3))." + +It should be noted that credentials come in many forms. Examples +include: group memberships; ticket-files; and Linux-PAM environment +variables. For this reason, it is important that the basic identity +of the user is established, by the application, prior to a call to +this function. For example, the default +.BR Linux-PAM +environment variables should be set and also +.BR initgroups "(2) " +(or equivalent) should have been performed. + +.SH "VALID FLAGS" +.TP +.BR PAM_ESTABLISH_CRED +initialize the credentials for the user. + +.TP +.BR PAM_DELETE_CRED +delete the user's credentials. + +.TP +.BR PAM_REINITIALIZE_CRED +delete and then initialize the user's credentials. + +.TP +.BR PAM_REFRESH_CRED +extend the lifetime of the existing credentials. + +.SH "RETURN VALUE" + +On success +.BR PAM_SUCCESS +is returned, all other return values should be treated as errors. + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_authenticate "(3), " +.BR pam_strerror "(3)" +and +.BR pam_open_session "(3). " + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_start.3 b/Linux-PAM/doc/man/pam_start.3 new file mode 100644 index 00000000..159bf201 --- /dev/null +++ b/Linux-PAM/doc/man/pam_start.3 @@ -0,0 +1,98 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: pam_start.3,v 1.1.1.1 2001/04/29 04:16:53 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996-7 +.TH PAM_START 3 "1997 Feb 15" "Linux-PAM 0.56" "Application Programmers' Manual" +.SH NAME + +pam_start, pam_end \- activating Linux-PAM + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_start(const char " *service ", const char " *user ", const struct pam_conv " *conv ", pam_handle_t " **pamh_p ");" +.sp +.BI "int pam_end(pam_handle_t " *pamh ", int " pam_status ");" +.sp 2 +.SH DESCRIPTION +.TP +.B pam_start +Initialize the +.I Linux-PAM +library. Identifying the application with a particular +.IR service +name. The +.IR user "name" +can take the value +.IR NULL ", " +if not known at the time the interface is initialized. The +conversation structure is passed to the library via the +.IR conv +argument. (For a complete description of this and other structures +the reader is directed to the more verbose +.IR Linux-PAM +application developers' guide). Upon successful initialization, an +opaque pointer-handle for future access to the library is returned +through the contents of the +.IR pamh_p +pointer. + +.TP +.B pam_end +Terminate the +.B Linux-PAM +library. The service application associated with the +.IR pamh +handle, is terminated. The argument, +.IR pam_status ", " +passes the value most recently returned to the application from the +library; it indicates the manner in which the library should be +shutdown. Besides carrying a return value, this argument may be +logically OR'd with +.IR PAM_DATA_SILENT +to indicate that the module should not treat the call too +seriously. It is generally used to indicate that the current closing +of the library is in a +.IR fork "(2)ed" +process, and that the parent will take care of cleaning up things that +exist outside of the current process space (files etc.). + +.SH "RETURN VALUE" +.TP +.B pam_start +.TP +.B pam_end +On success, +.BR PAM_SUCCESS +is returned + +.SH ERRORS +May be translated to text with +.BR pam_strerror "(3). " + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. +.sp +Note, the +.BR PAM_DATA_SILENT +flag is pending acceptance with the DCE (as of 1996/12/4). + +.SH BUGS +.sp 2 +None known. + +.SH "SEE ALSO" + +.BR fork "(2), " +.BR pam_authenticate "(3), " +.BR pam_acct_mgmt "(3), " +.BR pam_open_session "(3), " +and +.BR pam_chauthtok "(3)." + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/pam_strerror.3 b/Linux-PAM/doc/man/pam_strerror.3 new file mode 100644 index 00000000..84622088 --- /dev/null +++ b/Linux-PAM/doc/man/pam_strerror.3 @@ -0,0 +1,51 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" ripped off from Rick Faith's getgroups man page +.\" $Id: pam_strerror.3,v 1.1.1.1 2001/04/29 04:16:54 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1996-7 +.TH PAM_STRERROR 3 "1999 Oct 4" "Linux-PAM 0.70" "Programmers' Manual" +.SH NAME + +pam_strerror \- return a textual description of a Linux-PAM error + +.SH SYNOPSIS +.B #include +.br +or, +.br +.B #include +.sp +.BI "const char * pam_strerror( pam_handle_t " "*pamh" ", int " pam_error ");" +.sp 2 +.SH DESCRIPTION +.B pam_strerror + +This function returns some text describing the +.BR Linux-PAM +error associated with the +.B pam_error +argument. + +.SH "RETURN VALUE" + +On success this function returns a description of the indicated +error. Should the function not recognize the error, ``Unknown +Linux-PAM error'' is returned. + +.SH "CONFORMING TO" +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +This function should be internationalized. + +.SH "SEE ALSO" + +.BR pam "(8). " + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/man/template-man b/Linux-PAM/doc/man/template-man new file mode 100644 index 00000000..5ba564a0 --- /dev/null +++ b/Linux-PAM/doc/man/template-man @@ -0,0 +1,52 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" $Id: template-man,v 1.1.1.1 2001/04/29 04:16:54 hartmans Exp $ +.\" Copyright (c) Andrew G. Morgan 1997 +.TH PAM_???? 2 "1997 Jan 4" "Linux-PAM 0.55" "Application Programmers' Manual" +.SH NAME + +function names \- brief summary of function + +.SH SYNOPSIS +.B #include +.sp +.BI "int pam_???(pam_handle_t " pamh ", int " flags); +.sp 2 +.SH DESCRIPTION +.TP +.B pam_??? +Here goes the +.I explanation +it may be quite +.IR long . +.TP +.SH "RETURN VALUE" +.B pam_??? +On success... +.BR PAM_SUCCESS +is returned +.TP +.SH ERRORS +May be translated to text with +.BR pam_strerror "(2). " + +.SH "CONFORMING TO" +.B pam_??? +DCE-RFC 86.0, October 1995. + +.SH BUGS +.sp 2 +none known. + +.SH "SEE ALSO" + +.BR pam_??? "(2), " +and +.BR pam_??? "(2). " + +Also, see the three +.BR Linux-PAM +Guides, for +.BR "System administrators" ", " +.BR "module developers" ", " +and +.BR "application developers" ". " diff --git a/Linux-PAM/doc/modules/README b/Linux-PAM/doc/modules/README new file mode 100644 index 00000000..b81f1d26 --- /dev/null +++ b/Linux-PAM/doc/modules/README @@ -0,0 +1,13 @@ +$Id: README,v 1.1.1.2 2002/09/15 20:08:28 hartmans Exp $ + +This directory contains a number of sgml sub-files. One for each +documented module. They contain a description of each module and give +some indication of its reliability. + +Additionally, there is a 'module.sgml-template' file which should be +used as a blank form for new module descriptions. + +Please feel free to submit amendments/comments etc. regarding these +files to: + + Andrew G. Morgan diff --git a/Linux-PAM/doc/modules/module.sgml-template b/Linux-PAM/doc/modules/module.sgml-template new file mode 100644 index 00000000..36ffe617 --- /dev/null +++ b/Linux-PAM/doc/modules/module.sgml-template @@ -0,0 +1,170 @@ + + + [*Familiar full name of module*, eg. The "allow all" module.] + +Synopsis + +

+ + +Module Name: +[ + insert the name of the module + + Blank is not permitted. +] + +Author[s]: + +[ + Insert author names here + + Blank is not permitted. If in doubt, put "unknown" if the + author wishes to remain anonymous, put "anonymous". +] + +Maintainer: + +[ + Insert names and date-begun of most recent maintainer. +] + +Management groups provided: + +[ + list the subset of four management groups supported by the + module. Choose from: account; authentication; password; + session. + + Blank entries are not permitted. Explicitly list all of the + management groups. In the future more may be added to libpam! +] + +Cryptographically sensitive: + +[ + Indicate whether this module contains code that can perform + reversible (strong) encryption. This field is primarily to + ensure that people redistributing it are not unwittingly + breaking laws... + + Modules may also require the presence of some local library + that performs the necessary encryption via some standard API. + In this case "uses API" can be included in this field. The + library in question should be added to the system requirements + below. + + Blank = no cryptography is used by module. +] + +Security rating: + +[ + Initially, this field should be left blank. If someone takes + it upon themselves to test the strength of the module, it can + later be filled. + + Blank = unknown. +] + +Clean code base: + +[ + This will probably be filled by the libpam maintainer. + It can be considered to be a public humiliation list. :*) + + I am of the opinion that "gcc -with_all_those_flags" is + trying to tell us something about whether the program + works as intended. Since there is currently no Security + evaluation procedure for modules IMHO this is not a + completely unreasonable indication (a lower bound anyway) + of the reliability of a module. + + This field would indicate the number and flavor of + warnings that gcc barfs up when trying to compile the + module as part of the tree. Is this too tyrannical? + + Blank = Linux-PAM maintainer has not tested it :) +] + +System dependencies: + +[ + here we list config files, dynamic libraries needed, system + resources, kernel options.. etc. + + Blank = nothing more than libc required. +] + +Network aware: + +[ + Does the module base its behavior on probing a network + connection? Does it expect to be protected by the + application? + + Blank = Ignorance of network. +] + + + +Overview of module + +[ + some text describing the intended actions of the module + general comments mainly (specifics in sections + below). +] + +[ + + [ now we have a level subsection for each of the + management groups. Include as many as there are groups + listed above in the synopsis ] + +[ Account | Authentication | Password | Session ] component + +

+ + +Recognized arguments: + +[ + List the supported arguments (leave their description for the + description below. + + Blank = no arguments are read and nothing is logged to syslog + about any arguments that are passed. Note, this + behavior is contrary to the RFC! +] + +Description: + +[ + This component of the module performs the task of ... +] + +Examples/suggested usage: + +[ + Here we list some doos and don'ts for this module. +] + + + + diff --git a/Linux-PAM/doc/modules/pam_access.sgml b/Linux-PAM/doc/modules/pam_access.sgml new file mode 100644 index 00000000..8a910d13 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_access.sgml @@ -0,0 +1,117 @@ + + + The access module + +Synopsis + +

+ + +Module Name: + +pam_access + + +Author[s]: + +Alexei Nogin <alexei@nogin.dnttm.ru> + +Maintainer: + +Management groups provided: + +account + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Requires a configuration file. By default +/etc/security/access.conf is used but this can be overridden. + +Network aware: + +Through + +Overview of module + +

+Provides logdaemon style login access control. + + Account component + +

+ + +Recognized arguments: + +accessfile=/path/to/file.conf; +fieldsep=separators + +Description: + +This module provides logdaemon style login access control based on +login names and on host (or domain) names, internet addresses (or +network numbers), or on terminal line names in case of non-networked +logins. Diagnostics are reported through +The behavior of this module can be modified with the following +arguments: + + +accessfile=/path/to/file.conf - +indicate an alternative fieldsep=separators - +this option modifies the field separator character that +fieldsep=| will cause the default `:' +character to be treated as part of a field value and `|' becomes the +field separator. Doing this is useful in conjuction with a system that +wants to use pam_access with X based applications, since the + + +Examples/suggested usage: + +Use of module is recommended, for example, on administrative machines +such as /etc/pam.d style configurations where your modules live +in /lib/security, start by adding the following line to +/etc/pam.d/login, /etc/pam.d/rlogin, +/etc/pam.d/rsh and /etc/pam.d/ftp: + + + +account required /lib/security/pam_access.so + + + +Note that use of this module is not effective unless your system ignores +.rhosts files. See the the pam_rhosts_auth documentation. + +A sample access.conf configuration file is included with the +distribution. + + diff --git a/Linux-PAM/doc/modules/pam_chroot.sgml b/Linux-PAM/doc/modules/pam_chroot.sgml new file mode 100644 index 00000000..2bc3e8af --- /dev/null +++ b/Linux-PAM/doc/modules/pam_chroot.sgml @@ -0,0 +1,86 @@ + + +Chroot + +Synopsis + +

+ + +Module Name: +Author: +Bruce Campbell <brucec@humbug.org.au> + +Maintainer: +Author; proposed on 20/11/96 - email for status + +Management groups provided: +account; session; authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: +Unwritten. + +System dependencies: + +Network aware: +Expects localhost. + + + +Overview of module + +

+This module is intended to provide a transparent wrapper around the +average user, one that puts them in a fake file-system (eg, their +'/' is really /some/where/else). + +

+Useful if you have several classes of users, and are slightly paranoid +about security. Can be used to limit who else users can see on the +system, and to limit the selection of programs they can run. + +Account component: + +

+Authentication component: + +

+Session component: + +

+ + + +Recognized arguments: +Arguments and logging levels for the PAM version are being worked on. + +Description: + +Examples/suggested usage: +Do provide a reasonable list of programs - just tossing 'cat', 'ls', 'rm', +'cp' and 'ed' in there is a bit... +

+Don't take it to extremes (eg, you can set up a separate environment for +each user, but its a big waste of your disk space.) + + + + diff --git a/Linux-PAM/doc/modules/pam_cracklib.sgml b/Linux-PAM/doc/modules/pam_cracklib.sgml new file mode 100644 index 00000000..de1d5df2 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_cracklib.sgml @@ -0,0 +1,304 @@ + + +Cracklib pluggable password strength-checker + +Synopsis + +

+ + +Module Name: + +pam_cracklib + +Author: + +Cristian Gafton <gafton@redhat.com> + +Maintainer: + +Author. + +Management groups provided: + +password + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Requires the system library /usr/lib/cracklib_dict. + +Network aware: + + + +Overview of module + +

+This module can be plugged into the +This module works in the following manner: it first calls the +Cracklib routine to check the strength of the password; if +crack likes the password, the module does an additional set of +strength checks. These checks are: + + + + +

+This module with no arguments will work well for standard unix +password encryption. With md5 encryption, passwords can be longer +than 8 characters and the default settings for this module can make it +hard for the user to choose a satisfactory new password. Notably, the +requirement that the new password contain no more than 1/2 of the +characters in the old password becomes a non-trivial constraint. For +example, an old password of the form "the quick brown fox jumped over +the lazy dogs" would be difficult to change... In addition, the +default action is to allow passwords as small as 5 characters in +length. For a md5 systems it can be a good idea to increase the +required minimum size of a password. One can then allow more credit +for different kinds of characters but accept that the new password may +share most of these characters with the old password. + +Password component + +

+ + +Recognized arguments: + +Description: + +The action of this module is to prompt the user for a password and +check its strength against a system dictionary and a set of rules for +identifying poor choices. + +

+The default action is to prompt for a single password, check its +strength and then, if it is considered strong, prompt for the password +a second time (to verify that it was typed correctly on the first +occasion). All being well, the password is passed on to subsequent +modules to be installed as the new authentication token. + +

+The default action may be modified in a number of ways using the +arguments recognized by the module: + + + other, +upper, lower and Cracklib itself, a "way too short" limit of 4 which is hard +coded in and a defined limit (6) that will be checked without +reference to minlen. If you want to allow passwords as short +as 5 characters you should either not use this module or recompile +the crack library and then recompile this module. + + = 0) This is the maximum credit for having digits in the new password. If +you have less than or = 0) This is the maximum credit for having upper case letters in the new +password. If you have less than or = 0) This is the maximum credit for having lower case letters in the new +password. If you have less than or = 0) This is the maximum credit for having other characters in the new +password. If you have less than or + +Examples/suggested usage: + +

+For an example of the use of this module, we show how it may be +stacked with the password component of + +# +# These lines stack two password type modules. In this example the +# user is given 3 opportunities to enter a strong password. The +# "use_authtok" argument ensures that the pam_pwdb module does not +# prompt for a password, but instead uses the one provided by +# pam_cracklib. +# +passwd password required pam_cracklib.so retry=3 +passwd password required pam_pwdb.so use_authtok + + + +

+Another example (in the /etc/pam.d/passwd format) is for the +case that you want to use md5 password encryption: + + +#%PAM-1.0 +# +# These lines allow a md5 systems to support passwords of at least 14 +# bytes with extra credit of 2 for digits and 2 for others the new +# password must have at least three bytes that are not present in the +# old password +# +password required pam_cracklib.so \ + difok=3 minlen=15 dcredit= 2 ocredit=2 +password required pam_pwdb.so use_authtok nullok md5 + + + +

+And here is another example in case you don't want to use credits: + + +#%PAM-1.0 +# +# These lines require the user to select a password with a minimum +# length of 8 and with at least 1 digit number, 1 upper case letter, +# and 1 other character +# +password required pam_cracklib.so \ + dcredit=-1 ucredit=-1 ocredit=-1 lcredit=0 minlen=8 +password required pam_pwdb.so use_authtok nullok md5 + + + +

+In this example we simply say that the password must have a minimum +length of 8: + + +#%PAM-1.0 +# +# These lines require the user to select a password with a mimimum +# length of 8. He gets no credits and he is not forced to use +# digit numbers, upper case letters etc. +# +password required pam_cracklib.so \ + dcredit=0 ucredit=0 ocredit=0 lcredit=0 minlen=8 +password required pam_pwdb.so use_authtok nullok md5 + + + + + + diff --git a/Linux-PAM/doc/modules/pam_deny.sgml b/Linux-PAM/doc/modules/pam_deny.sgml new file mode 100644 index 00000000..d8041d19 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_deny.sgml @@ -0,0 +1,177 @@ + + +The locking-out module + +Synopsis + +

+ + +Module Name: +pam_deny + +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +current Management groups provided: +account; authentication; password; session + +Cryptographically sensitive: + +Security rating: + +Clean code base: +clean. + +System dependencies: + +Network aware: + + + +Overview of module + +

+This module can be used to deny access. It always indicates a failure +to the application through the PAM framework. As is commented in the +overview section , this module +might be suitable for using for default (the Account component + +

+ + +Recognized arguments: + +Description: + +This component does nothing other than return a failure. The +failure type is Examples/suggested usage: + +Stacking this module with type +The following example would make it impossible to login: + + +# +# add this line to your other login entries to disable all accounts +# +login account required pam_deny.so + + + + + +Authentication component + +

+ + +Recognized arguments: + +Description: + +This component does nothing other than return a failure. The failure +type is Examples/suggested usage: + +To deny access to default applications with this component of the + + +# +# add this line to your existing OTHER entries to prevent +# authentication succeeding with default applications. +# +OTHER auth required pam_deny.so + + + + + +Password component + +

+ + +Recognized arguments: + +Description: + +This component of the module denies the user the opportunity to change +their password. It always responds with Examples/suggested usage: + +This module should be used to prevent an application from updating the +applicant user's password. For example, to prevent + +# +# add this line to your other login entries to prevent the login +# application from being able to change the user's password. +# +login password required pam_deny.so + + + + + +Session component + +

+ + +Recognized arguments: + +Description: + +This aspect of the module prevents an application from starting a +session on the host computer. + +Examples/suggested usage: + +Together with another session module, that displays a message of the +day perhaps ( + +# +# An example to see how to configure login to refuse the user a +# session (politely) +# +login session required pam_motd.so \ + motd=/etc/system_time +login session required pam_deny.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_env.sgml b/Linux-PAM/doc/modules/pam_env.sgml new file mode 100644 index 00000000..0ca18fe4 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_env.sgml @@ -0,0 +1,141 @@ + + +Set/unset environment variables + +Synopsis + +

+ + +Module Name: +Author: +Dave Kinchlea <kinch@kinch.ark.com> + +Maintainer: +Author + +Management groups provided: +Authentication (setcred) + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +/etc/security/pam_env.conf + +Network aware: + + + +Overview of module + +

+This module allows the (un)setting of environment variables. Supported +is the use of previously set environment variables as well as +PAM_ITEMs such as PAM_RHOST. + +Authentication component + +

+ + +Recognized arguments: +Description: +This module allows you to (un)set arbitrary environment variables +using fixed strings, the value of previously set environment variables +and/or +All is controlled via a configuration file (by default, +/etc/security/pam_env.conf but can be overriden with +conffile argument). Each line starts with the variable name, +there are then two possible options for each variable DEFAULT +and OVERRIDE. DEFAULT allows an administrator to +set the value of the variable to some default value, if none is +supplied then the empty string is assumed. The OVERRIDE +option tells pam_env that it should enter in its value (overriding the +default value) if there is one to use. OVERRIDE is not used, +"" is assumed and no override will be done. + +

+ + +VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] + + + +

+(Possibly non-existent) environment variables may be used in values +using the ${string} syntax and (possibly +non-existent) @{string} syntax. Both the $ +and @ characters can be backslash-escaped to be used +as literal values (as in \$. Double quotes may +be used in values (but not environment variable names) when white +space is needed the full value must be delimited by the quotes and +embedded or escaped quotes are not supported. + +

+This module can also parse a file with simple KEY=VAL pairs +on seperate lines (/etc/environment by default). You can +change the default file to parse, with the +The behavior of this module can be modified with one of the following +flags: + +

+ + +/etc/security/pam_env.conf is used as +the configuration file. This option overrides the default. You must +supply a complete path + file name. + +/etc/environment is used to load KEY=VAL +pairs directly into the env. This option overrides the default. You must +supply a complete path + file name. + + + +Examples/suggested usage: + +See sample pam_env.conf for more information and examples. + + + + + + + + + + + + + + diff --git a/Linux-PAM/doc/modules/pam_filter.sgml b/Linux-PAM/doc/modules/pam_filter.sgml new file mode 100644 index 00000000..1d582abc --- /dev/null +++ b/Linux-PAM/doc/modules/pam_filter.sgml @@ -0,0 +1,150 @@ + + +The filter module + +Synopsis + +

+ + +Module Name: + +pam_filter + +Author: + +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: + +Author. + +Management groups provided: + +account; authentication; password; session + +Cryptographically sensitive: + +Not yet. + +Security rating: + +Clean code base: + +This module compiles cleanly on Linux based systems. + +System dependencies: + +To function it requires Network aware: + + + +Overview of module + +

+This module was written to offer a plug-in alternative to programs +like ttysnoop (XXX - need a reference). Since writing a filter that +performs this function has not occurred, it is currently only a toy. +The single filter provided with the module simply transposes upper and +lower case letters in the input and output streams. (This can be very +annoying and is not kind to termcap based editors). + +Account+Authentication+Password+Session components + +

+ + +Recognized arguments: + +Description: + +Each component of the module has the potential to invoke the desired +filter. The filter is always +The behavior of the module can be significantly altered by the +arguments passed to it in the + +Permitted values for +For the case of the account component. Either +For the case of the password component, + +Examples/suggested usage: + +At the time of writing there is little real use to be made of this +module. For fun you might try adding the following line to your +login's configuration entries + + +# +# An example to see how to configure login to transpose upper and +# lower case letters once the user has logged in(!) +# +login session required pam_filter.so \ + run1 /usr/sbin/pam_filter/upperLOWER + + + + + + diff --git a/Linux-PAM/doc/modules/pam_ftp.sgml b/Linux-PAM/doc/modules/pam_ftp.sgml new file mode 100644 index 00000000..3ea43713 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_ftp.sgml @@ -0,0 +1,93 @@ + + +Anonymous access module + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author. + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: +prompts for email address of user; easily spoofed (XXX - needs work) + + + +Overview of module + +

+The purpose of this module is to provide a pluggable anonymous ftp +mode of access. + +Authentication component + +

+ + +Recognized arguments: +Description: + +This module intercepts the user's name and password. If the name is +`` +The behavior of the module can be modified with the following flags: + + + +Examples/suggested usage: + +An example of the use of this module is provided in the configuration +file section . With care, this +module could be used to provide new/temporary account anonymous +login. + + + + diff --git a/Linux-PAM/doc/modules/pam_group.sgml b/Linux-PAM/doc/modules/pam_group.sgml new file mode 100644 index 00000000..770933bc --- /dev/null +++ b/Linux-PAM/doc/modules/pam_group.sgml @@ -0,0 +1,108 @@ + + +The group access module + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author. + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: +Sensitive to Clean code base: + +System dependencies: +Requires an /etc/security/group.conf file. Can be compiled +with or without Network aware: +Only through correctly set + +Overview of module + +

+This module provides group-settings based on the user's name and the +terminal they are requesting a given service from. It takes note of +the time of day. + +Authentication component + +

+ + +Recognized arguments: + +Description: + +This module does not authenticate the user, but instead it grants +group memberships (in the credential setting phase of the +authentication module) to the user. Such memberships are based on the +service they are applying for. The group memberships are listed in +text form in the /etc/security/group.conf file. + +Examples/suggested usage: + +For this module to function correctly there must be a correctly +formatted /etc/security/groups.conf file present. The format +of this file is as follows. Group memberships are given based on the +service application satisfying any combination of lines in the +configuration file. Each line (barring comments which are preceded by +` + +services ; ttys ; users ; times ; groups + + +Here the first four fields share the syntax of the pam_time +configuration file; /etc/security/pam_time.conf, and the last +field, the +As stated in above this module's usefulness relies on the file-systems +accessible to the user. The point being that once granted the +membership of a group, the user may attempt to create a +The pam_group module fuctions in parallel with the +/etc/group file. If the user is granted any groups based on +the behavior of this module, they are granted in addition to +those entries /etc/group (or equivalent). + + + + diff --git a/Linux-PAM/doc/modules/pam_issue.sgml b/Linux-PAM/doc/modules/pam_issue.sgml new file mode 100644 index 00000000..1f617e3b --- /dev/null +++ b/Linux-PAM/doc/modules/pam_issue.sgml @@ -0,0 +1,120 @@ + + +Add issue file to user prompt + +Synopsis + +

+ + +Module Name: +Author: +Ben Collins <bcollins@debian.org> + +Maintainer: +Author + +Management groups provided: +Authentication (pam_sm_authenticate) + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: + + + +Overview of module + +

+This module prepends the issue file (/etc/issue by default) when +prompting for a username. + +Authentication component + +

+ + +Recognized arguments: +Description: +This module allows you to prepend an issue file to the username prompt. It +also by default parses escape codes in the issue file similar to some +common getty's (using \x format). +

+Recognized escapes: + + + + +

+The behavior of this module can be modified with one of the following +flags: + +

+ + + + +Examples/suggested usage: + +login auth pam_issue.so issue=/etc/issue + + + + diff --git a/Linux-PAM/doc/modules/pam_krb4.sgml b/Linux-PAM/doc/modules/pam_krb4.sgml new file mode 100644 index 00000000..2fc8518e --- /dev/null +++ b/Linux-PAM/doc/modules/pam_krb4.sgml @@ -0,0 +1,126 @@ + + +The Kerberos 4 module. + +Synopsis + +

+ + +Module Name: +Author: +Derrick J. Brashear <shadow@dementia.org> + +Maintainer: +Author. + +Management groups provided: +authentication; password; session + +Cryptographically sensitive: +uses API + +Security rating: + +Clean code base: + +System dependencies: +libraries - Network aware: +Gets Kerberos ticket granting ticket via a Kerberos key distribution +center reached via the network. + + + +Overview of module + +

+This module provides an interface for doing Kerberos verification of a +user's password, getting the user a Kerberos ticket granting ticket +for use with the Kerberos ticket granting service, destroying the +user's tickets at logout time, and changing a Kerberos password. + + Session component + +

+ + +Recognized arguments: + +Description: + +This component of the module currently sets the user's Examples/suggested usage: + +This part of the module won't be terribly useful until we can change +the environment from within a + + Password component + +

+ + +Recognized arguments: +Description: + +This component of the module changes a user's Kerberos password +by first getting and using the user's old password to get +a session key for the password changing service, then sending +a new password to that service. + +Examples/suggested usage: + +This should only be used with a real Kerberos v4 + + Authentication component + +

+ + +Recognized arguments: +Description: + +This component of the module verifies a user's Kerberos password +by requesting a ticket granting ticket from the Kerberos server +and optionally using it to attempt to retrieve the local computer's +host key and verifying using the key file on the local machine if +one exists. + +It also writes out a ticket file for the user to use later, and +deletes the ticket file upon logout (not until Examples/suggested usage: + +This module can be used with a real Kerberos server using MIT +v4 Kerberos keys. The module or the system Kerberos libraries +may be modified to support AFS style Kerberos keys. Currently +this is not supported to avoid cryptography constraints. + + + + diff --git a/Linux-PAM/doc/modules/pam_lastlog.sgml b/Linux-PAM/doc/modules/pam_lastlog.sgml new file mode 100644 index 00000000..e79723b3 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_lastlog.sgml @@ -0,0 +1,119 @@ + + +The last login module + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author + +Management groups provided: +auth + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +uses information contained in the /var/log/lastlog file. + +Network aware: + + + +Overview of module + +

+This session module maintains the /var/log/lastlog file. Adding +an open entry when called via the pam_open_seesion() function +and completing it when pam_close_session() is called. This +module can also display a line of information about the last login of +the user. If an application already performs these tasks, it is not +necessary to use this module. + +Session component + +

+ + +Recognized arguments: +Description: + +

+This module can be used to provide a ``Last login on ...'' +message. when the user logs into the system from what ever application +uses the PAM libraries. In addition, the module maintains the +/var/log/lastlog file. + +

+The behavior of this module can be modified with one of the following +flags: + +

+ +/var/log/lastlog file. + +/var/log/lastlog file does not contain any old entries +for the user, indicate that the user has never previously logged in +with a ``welcome..." message. + + + +Examples/suggested usage: + +This module can be used to indicate that the user has new mail when +they /etc/pam.d/XXX file: + + +# +# When were we last here? +# +session optional pam_lastlog.so + + + +

+Note, some applications may perform this function themselves. In such +cases, this module is not necessary. + + + + diff --git a/Linux-PAM/doc/modules/pam_limits.sgml b/Linux-PAM/doc/modules/pam_limits.sgml new file mode 100644 index 00000000..65ce6d82 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_limits.sgml @@ -0,0 +1,247 @@ + + +The resource limits module + +Synopsis + +

+ + +Module Name: +Authors: +Cristian Gafton <gafton@redhat.com> +Thanks are also due to Elliot Lee <sopwith@redhat.com> +for his comments on improving this module. + +Maintainer: +Cristian Gafton - 1996/11/20 + +Management groups provided: +session + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +requires an /etc/security/limits.conf file and kernel support +for resource limits. Also uses the library, Network aware: + + + +Overview of module + +

+This module, through the Session component + +

+ + +Recognized arguments: +conf=/path/to/file.conf; change_uid; +utmp_early + +Description: + +Through the contents of the configuration file, +/etc/security/limits.conf, resource limits are placed on +users' sessions. Users of +The behavior of this module can be modified with the following +arguments: + + +conf=/path/to/file.conf - +indicate an alternative + +Examples/suggested usage: + +In order to use this module the system administrator must first create +a /etc/security/limits.conf). This file describes the resource +limits the superuser wishes to impose on users and groups. No limits +are imposed on +Each line of the configuration file describes a limit for a user in +the form: + + + + + + +

+The fields listed above should be filled as follows... +<domain> can be: + + a username + a groupname, with @group syntax + the wild-card the wild-card %group syntax + + +

+<type> can have the three values: + + + + +

+<item> can be one of the following: + + + +

+Note, if you specify a type of ``-'' but neglect to supply the + +In general, individual limits have priority over group limits, so if +you impose no limits for +Also, please note that all limit settings are set +In the +The +The following is an example configuration file: + + +# EXAMPLE /etc/security/limits.conf file: +# ======================================= +# +* soft core 0 +* hard rss 10000 +@student hard nproc 20 +@faculty soft nproc 20 +@faculty hard nproc 50 +ftp hard nproc 0 +@student - maxlogins 4 + + +Note, the use of +Note, that wild-cards + %group is specified + +See the following examples: + + +# EXAMPLE /etc/security/limits.conf file: +# +* - maxlogins 2 +@faculty - maxlogins 4 +% - maxlogins 30 +%student - maxlogins 10 + + +Explanation: every user can login 2 times, members of the +For the services that need resources limits (login for example) put +the following line in /etc/pam.conf as the last line for that +service (usually after the pam_unix session line: + + +# +# Resource limits imposed on login sessions via pam_limits +# +login session required pam_limits.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_listfile.sgml b/Linux-PAM/doc/modules/pam_listfile.sgml new file mode 100644 index 00000000..f39d8bc6 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_listfile.sgml @@ -0,0 +1,138 @@ + + +The list-file module + +Synopsis + +

+ + +Module Name: +Author: +Elliot Lee <sopwith@cuc.edu> + +Maintainer: +Red Hat Software: +Michael K. Johnson <johnsonm@redhat.com> 1996/11/18 +(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: +clean + +System dependencies: + +Network aware: + + + +Overview of module + +

+The list-file module provides a way to deny or allow services based on +an arbitrary file. + +Authentication component + +

+ + +Recognized arguments: + +onerr=succeed|fail; +sense=allow|deny; +file=filename; +item=user|tty|rhost|ruser|group|shell +apply=user|@group + +Description: + +The module gets the item of the type specified -- user specifies +the username, PAM_USER; tty specifies the name of the terminal +over which the request has been made, PAM_TTY; rhost specifies +the name of the remote host (if any) from which the request was made, +PAM_RHOST; and ruser specifies the name of the remote user +(if available) who made the request, PAM_RUSER -- and looks for +an instance of that item in the file filename. filename +contains one line per item listed. If the item is found, then if +sense=allow, PAM_SUCCESS is returned, causing the +authorization request to succeed; else if sense=deny, +PAM_AUTH_ERR is returned, causing the authorization +request to fail. + +

+If an error is encountered (for instance, if filename +does not exist, or a poorly-constructed argument is encountered), +then if onerr=succeed, PAM_SUCCESS is returned, +otherwise if onerr=fail, PAM_AUTH_ERR or +PAM_SERVICE_ERR (as appropriate) will be returned. + +

+An additional argument, apply=, can be used to restrict the +application of the above to a specific user +(apply=username) or a given group +(apply=@groupname). This added restriction is only +meaningful when used with the +Besides this last one, all arguments should be specified; do not count +on any default behavior, as it is subject to change. + +

+No credentials are awarded by this module. + +Examples/suggested usage: + +Classic ``ftpusers'' authentication can be implemented with this entry +in /etc/pam.conf: + + +# +# deny ftp-access to users listed in the /etc/ftpusers file +# +ftp auth required pam_listfile.so \ + onerr=succeed item=user sense=deny file=/etc/ftpusers + + +Note, users listed in /etc/ftpusers file are +(counterintuitively) +To allow login access only for certain users, you can use a + + +# +# permit login to users listed in /etc/loginusers +# +login auth required pam_listfile.so \ + onerr=fail item=user sense=allow file=/etc/loginusers + + + +

+For this example to work, all users who are allowed to use the login +service should be listed in the file /etc/loginusers. Unless +you are explicitly trying to lock out root, make sure that when you do +this, you leave a way for root to log in, either by listing root in +/etc/loginusers, or by listing a user who is able to + + diff --git a/Linux-PAM/doc/modules/pam_mail.sgml b/Linux-PAM/doc/modules/pam_mail.sgml new file mode 100644 index 00000000..397df29e --- /dev/null +++ b/Linux-PAM/doc/modules/pam_mail.sgml @@ -0,0 +1,142 @@ + + +The mail module + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author + +Management groups provided: +Authentication (credential) +Session (open) + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Default mail directory /var/spool/mail/ + +Network aware: + + + +Overview of module + +

+This module looks at the user's mail directory and indicates +whether the user has any mail in it. + +Session component + +

+ + +Recognized arguments: +Description: + +This module provides the ``you have new mail'' service to the user. It +can be plugged into any application that has credential hooks. It gives a +single message indicating the +The behavior of this module can be modified with one of the following +flags: + +

+ +/var/spool/mail. Note, if the supplied /var/spool/mail/u/s/user. + + + +Examples/suggested usage: + +This module can be used to indicate that the user has new mail when +they /etc/pam.conf file: + + +# +# do we have any mail? +# +login session optional pam_mail.so + + + +

+Note, if the mail spool file (be it /var/spool/mail/$USER or +a pathname given with the dir= parameter) is a directory then +pam_mail assumes it is in the Qmail Maildir format. + +

+Note, some applications may perform this function themselves. In such +cases, this module is not necessary. + + + +Authentication component + +

+Then authentication companent works the same as the session component, +except that everything is done during the pam_setcred() phase. + + diff --git a/Linux-PAM/doc/modules/pam_mkhomedir.sgml b/Linux-PAM/doc/modules/pam_mkhomedir.sgml new file mode 100644 index 00000000..075e16f9 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_mkhomedir.sgml @@ -0,0 +1,83 @@ + + +Create home directories on initial login + +Synopsis + +

+ + +Module Name: +Author: +Jason Gunthorpe <jgg@ualberta.ca> + +Maintainer: +Ben Collins <bcollins@debian.org> + +Management groups provided: +Session + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: + + + +Overview of module + +

+Creates home directories on the fly for authenticated users. + +Session component + +

+ + +Recognized arguments: +Description: +This module is useful for distributed systems where the user account is +managed in a central database (such as NIS, NIS+, or LDAP) and accessed +through miltiple systems. It frees the administrator from having to create +a default home directory on each of the systems by creating it upon the +first succesfully authenticated login of that user. The skeleton directory +(usually /etc/skel/) is used to copy default files and also set's a umask +for the creation. + +

+The behavior of this module can be modified with one of the following +flags: + +

+ + + + +Examples/suggested usage: + +session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 + + + + diff --git a/Linux-PAM/doc/modules/pam_motd.sgml b/Linux-PAM/doc/modules/pam_motd.sgml new file mode 100644 index 00000000..8ddc6392 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_motd.sgml @@ -0,0 +1,77 @@ + + +Output the motd file + +Synopsis + +

+ + +Module Name: +Author: +Ben Collins <bcollins@debian.org> + +Maintainer: +Author + +Management groups provided: +Session (open) + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: + + + +Overview of module + +

+This module outputs the motd file (/etc/motd by default) upon +successful login. + +Session component + +

+ + +Recognized arguments: +Description: +This module allows you to have arbitrary motd's (message of the day) +output after a succesful login. By default this file is /etc/motd, +but is configurable to any file. + +

+The behavior of this module can be modified with one of the following +flags: + +

+ + + + +Examples/suggested usage: + +login session pam_motd.so motd=/etc/motd + + + + diff --git a/Linux-PAM/doc/modules/pam_nologin.sgml b/Linux-PAM/doc/modules/pam_nologin.sgml new file mode 100644 index 00000000..e2463570 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_nologin.sgml @@ -0,0 +1,81 @@ + + +The no-login module + +Synopsis + +

+ + +Module Name: +Author: +Written by Michael K. Johnson <johnsonm@redhat.com> + +Maintainer: + +Management groups provided: +account; authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: + + + +Overview of module + +

+Provides standard Unix Authentication component + +

+ + +Recognized arguments: +successok, file=<Description: + +Provides standard Unix /etc/nologin exists, only root is allowed to log in; other +users are turned away with an error message (and the module returns +/etc/nologin. + +

+If the file /etc/nologin does not exist, this module defaults +to returning +The administrator can override the default nologin file with the +Examples/suggested usage: + +In order to make this module effective, all login methods should be +secured by it. It should be used as a required method listed +before any sufficient methods in order to get standard Unix +nologin semantics. Note, the use of + + diff --git a/Linux-PAM/doc/modules/pam_permit.sgml b/Linux-PAM/doc/modules/pam_permit.sgml new file mode 100644 index 00000000..969e6b84 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_permit.sgml @@ -0,0 +1,83 @@ + + +The promiscuous module + +Synopsis + +

+ + +Module Name: +pam_permit + +Author: +Andrew G. Morgan, <morgan@kernel.org> + +Maintainer: +Linux-PAM maintainer. + +Management groups provided: +account; authentication; password; session + +Cryptographically sensitive: + +Security rating: +VERY LOW. Use with extreme caution. + +Clean code base: +Clean. + +System dependencies: + +Network aware: + + + +Overview of module + +

+This module is very dangerous. It should be used with extreme +caution. Its action is always to permit access. It does nothing else. + +Account+Authentication+Password+Session components + +

+ + +Recognized arguments: + +Description: + +No matter what management group, the action of this module is to +simply return +In the case of authentication, the user's name will be acquired. Many +applications become confused if this name is unknown. + +Examples/suggested usage: + +It is seldom a good idea to use this module. However, it does have +some legitimate uses. For example, if the system-administrator wishes +to turn off the account management on a workstation, and at the same +time continue to allow logins, then she might use the following +configuration file entry for login: + + +# +# add this line to your other login entries to disable account +# management, but continue to permit users to log in... +# +login account required pam_permit.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_pwdb.sgml b/Linux-PAM/doc/modules/pam_pwdb.sgml new file mode 100644 index 00000000..df0cb329 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_pwdb.sgml @@ -0,0 +1,249 @@ + + +The Password-Database module + +Synopsis + +

+ + +Module Name: +pam_pwdb + +Author: +Cristian Gafton <gafton@redhat.com> +and Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Red Hat. + +Management groups provided: +account; authentication; password; session + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Requires properly configured Network aware: + + + +Overview of module + +

+This module is a pluggable replacement for the libpwdb. + +Account component + +

+ + +Recognized arguments: +Description: + +The Examples/suggested usage: + +In its accounting mode, this module can be inserted as follows: + + +# +# Ensure users account and password are still active +# +login account required pam_pwdb.so + + + + + +Authentication component + +

+ + +Recognized arguments: +Description: + +The +The default action of this module is to not permit the user access to +a service if their +When given the argument +The argument, nodelay, can be used to discourage the +authentication component from requesting a delay should the +authentication as a whole fail. The default action is for the module +to request a delay-on-failure of the order of one second. + +

+Remaining arguments, supported by the other functions of this module, +are silently ignored. Other arguments are logged as errors through + +A helper binary, pwdb_chkpwd, is provided to check the user's +password when it is stored in a read protected database. This binary +is very simple and will only check the password of the user invoking +it. It is called transparently on behalf of the user by the +authenticating component of this module. In this way it is possible +for applications like xlock to work without being setuid-root. + +

+The likeauth argument makes the module return the same value +when called as a credential setting module and an authentication +module. This will help libpam take a sane path through the auth +component of your configuration file. + +Examples/suggested usage: + +The correct functionality of this module is dictated by having an +appropriate /etc/pwdb.conf file, the user +databases specified there dictate the source of the authenticated +user's record. + + + +Password component + +

+ + +Recognized arguments: +Description: + +This part of the +In the case of conventional unix databases (which store the password +encrypted) the +The +The argument +The +The Examples/suggested usage: + +An example of the stacking of this module with respect to the +pluggable password checking module, + +Session component + +

+ + +Recognized arguments: + +Description: + +No arguments are recognized by this module component. Its action is +simply to log the username and the service-type to +Examples/suggested usage: + +The use of the session modules is straightforward: + + +# +# pwdb - unix like session opening and closing +# +login session required pam_pwdb.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_radius.sgml b/Linux-PAM/doc/modules/pam_radius.sgml new file mode 100644 index 00000000..b452bebd --- /dev/null +++ b/Linux-PAM/doc/modules/pam_radius.sgml @@ -0,0 +1,117 @@ + + +The RADIUS session module + +Synopsis + +

+ + +Module Name: +Author: +Cristian Gafton <gafton@redhat.com> + +Maintainer: +Author. + +Management groups provided: +session + +Cryptographically sensitive: +This module does not deal with passwords + +Security rating: + +Clean code base: +gcc reports 1 warning when compiling /usr/include/rpc/clnt.h. +Hey, is not my fault ! + +System dependencies: + +Network aware: + +yes; this is a network module (independent of application). + + + +Overview of module + +

+This module is intended to provide the session service for users +authenticated with a RADIUS server. At the present stage, the only +option supported is the use of the RADIUS server as an accounting +server. + +Session component + +

+ + +Recognized arguments: + +Description: + +This module is intended to provide the session service for users +authenticated with a RADIUS server. At the present stage, the only +option supported is the use of the RADIUS server as an +(There are few things which needs to be cleared out first in +the PAM project until one will be able to use this module and expect +it to magically start pppd in response to a RADIUS server command to +use PPP for this user, or to initiate a telnet connection to another +host, or to hang and call back the user using parameters provided in +the RADIUS server response. Most of these things are better suited for +the radius login application. I hope to make available Real Soon (tm) +patches for the login apps to make it work this way.) + +

+When opening a session, this module sends an ``Accounting-Start'' +message to the RADIUS server, which will log/update/whatever a +database for this user. On close, an ``Accounting-Stop'' message is +sent to the RADIUS server. + +

+This module has no other prerequisites for making it work. One can +install a RADIUS server just for fun and use it as a centralized +accounting server and forget about wtmp/last/sac etc. . + +Examples/suggested usage: + +For the services that need this module (/etc/pam.conf as the last line for that +service (usually after the pam_unix session line): + + +login session required pam_radius.so + + +Replace +This module make extensive use of the API provided in libpwdb +0.54preB or later. By default, it will read the radius server +configuration (hostname and secret) from /etc/raddb/server. +This is a default compiled into libpwdb, and curently there is no way to +modify this default without recompiling libpwdb. I am working on +extending the radius support from libpwdb to provide a possibility +to make this runtime-configurable. + +Also please note that libpwdb will require also the RADIUS +dictionary to be present (/etc/raddb/dictionary). + + + + + diff --git a/Linux-PAM/doc/modules/pam_rhosts.sgml b/Linux-PAM/doc/modules/pam_rhosts.sgml new file mode 100644 index 00000000..4b9d1a89 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_rhosts.sgml @@ -0,0 +1,164 @@ + + +The rhosts module + +Synopsis + +

+ + +Module Name: +Author: +Al Longyear <longyear@netcom.com> + +Maintainer: + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: +Clean. + +System dependencies: + +Network aware: +Standard + +Overview of module + +

+This module performs the standard network authentication for services, +as used by traditional implementations of Authentication component + +

+ + +Recognized arguments: +Description: + +The authentication mechanism of this module is based on the contents +of two files; /etc/hosts.equiv (or #include <netdb.h>) and ~/.rhosts. Firstly, +hosts listed in the former file are treated as equivalent to the +localhost. Secondly, entries in the user's own copy of the latter file +is used to map "/etc/hosts.equiv and their remote account +is identical to their local one, or if their remote account has an +entry in their personal configuration file. + +

+Some restrictions are applied to the attributes of the user's personal +configuration file: it must be a regular file (as defined by + +The module authenticates a remote user (internally specified by the +item +In the case of /etc/host.equiv file is +hosts_equiv_rootok option +should be used. Instead, the superuser must have a correctly configured +personal configuration file. + +

+The behavior of the module is modified by flags: + + + + +/etc/hosts.equiv file. + + +/etc/hosts.equiv for superuser. Without this +option /etc/hosts.equiv is not consulted for the superuser account. +This option has no effect if the no_hosts_equiv option is used. + + +~/.rhosts. + + +~/.rhosts file must not be writable by anyone +other than its owner. This option overlooks group write access in the +case that the group owner of this file has the same name as the +user being authenticated. To lessen the security problems associated +with this option, the module also checks that the user is the only +member of their private group. + + + + +Examples/suggested usage: + +To allow users to login from trusted remote machines, you should try +adding the following line to your /etc/pam.conf file + + +# +# No passwords required for users from hosts listed above. +# +login auth sufficient pam_rhosts_auth.so no_rhosts + + +Note, in this example, the system administrator has turned off all +/etc/host.equiv file, by replacing + + diff --git a/Linux-PAM/doc/modules/pam_rootok.sgml b/Linux-PAM/doc/modules/pam_rootok.sgml new file mode 100644 index 00000000..e882f4d5 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_rootok.sgml @@ -0,0 +1,85 @@ + + +The root access module + +Synopsis + +

+ + +Module Name: +pam_rootok + +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Linux-PAM maintainer + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: +Clean. + +System dependencies: + +Network aware: + + + +Overview of module + +

+This module is for use in situations where the superuser wishes +to gain access to a service without having to enter a password. + +Authentication component + +

+ + +Recognized arguments: +Description: + +This module authenticates the user if their Examples/suggested usage: + +In the case of the + +# +# su authentication. Root is granted access by default. +# +su auth sufficient pam_rootok.so +su auth required pam_unix_auth.so + + + +

+Note. For programs that are run by the superuser (or started when the +system boots) this module should not be used to authenticate users. + + + + diff --git a/Linux-PAM/doc/modules/pam_securetty.sgml b/Linux-PAM/doc/modules/pam_securetty.sgml new file mode 100644 index 00000000..f500b8b2 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_securetty.sgml @@ -0,0 +1,72 @@ + + +The securetty module + +Synopsis + +

+ + +Module Name: +Author[s]: +Elliot Lee <sopwith@cuc.edu> + +Maintainer: +Red Hat Software: + +(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +/etc/securetty file + +Network aware: + +Requires the application to fill in the PAM_TTY item +correctly in order to act meaningfully. + + + +Overview of module + +

+Provides standard Unix securetty checking. + +Authentication component + +

+ + +Recognized arguments: + +Description: + +Provides standard Unix securetty checking, which causes authentication +for root to fail unless PAM_TTY is set to a string listed in +the /etc/securetty file. For all other users, it succeeds. + +Examples/suggested usage: + +For canonical usage, should be listed as a required +authentication method before any sufficient authentication +methods. + + + + diff --git a/Linux-PAM/doc/modules/pam_tally.sgml b/Linux-PAM/doc/modules/pam_tally.sgml new file mode 100644 index 00000000..a2d03435 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_tally.sgml @@ -0,0 +1,191 @@ + + +The login counter (tallying) module + +Synopsis + +

+ + +Module Name: +pam_tally + +Author[s]: +Tim Baverstock + +Maintainer: + +Management groups provided: +auth; account + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +A faillog file (default location /var/log/faillog) + +Network aware: + + + +Overview of module + +

+This module maintains a count of attempted accesses, can reset count +on success, can deny access if too many attempts fail. + +

+pam_tally comes in two parts: pam_tally.so and +pam_tally. The former is the PAM module and the latter, a +stand-alone program. pam_tally is an (optional) application +which can be used to interrogate and manipulate the counter file. It +can display users' counts, set individual counts, or clear all +counts. Setting artificially high counts may be useful for blocking +users without changing their passwords. For example, one might find it +useful to clear all counts every midnight from a cron job. + +

+The counts file is organized as a binary-word array, indexed by +uid. You can probably make sense of it with od, if you don't +want to use the supplied appliction. + +

+Note, there are some outstanding issues with this module: +pam_tally is very dependant on getpw*() - a database +of usernames would be much more flexible; the `keep a count of current +logins' bit has been #ifdef'd out and you can only reset the +counter on successful authentication, for now. + +Generic options accepted by both components +

+ + onerr=(succeed|fail): + if something weird happens, such as unable to open the file, how + should the module react? + file=/where/to/keep/counts: + specify the file location for the counts. + The default location is /var/log/faillog. + + +Authentication component + +

+ + +Recognized arguments: +onerr=(succeed|fail); +file=/where/to/keep/counts; +no_magic_root + +Description: + +

+The authentication component of this module increments the attempted +login counter. + +

+Examples/suggested usage: + +

+The module argument no_magic_root is used to indicate that if +the module is invoked by a user with uid=0, then the counter is +incremented. The sys-admin should use this for daemon-launched +services, like telnet/rsh/login. For user +launched services, like su, this argument should be omitted. + +

+By way of more explanation, when a process already running as root +tries to access some service, the access is magic, and +bypasses pam_tally's checks: this is handy for suing +from root into an account otherwise blocked. However, for services +like telnet or login, which always effectively run +from the root account, root (ie everyone) shouldn't be granted this +magic status, and the flag `no_magic_root' should be set in this +situation, as noted in the summary above. + + + +Account component + +

+ + +Recognized arguments: +onerr=(succeed|fail); +file=/where/to/keep/counts; +deny=n; +no_magic_root; +even_deny_root_account; +reset; +no_reset; +per_user; +no_lock_time + +Description: + +

+The account component can deny access and/or reset the attempts +counter. It also checks to make sure that the counts file is a plain +file and not world writable. + +Examples/suggested usage: + +

+The deny=n option is used to deny access if tally +for this user exceeds n. The presence of +deny=n changes the default for +reset/no_reset to reset, unless the user +trying to gain access is root and the no_magic_root option +has NOT been specified. + +

+The no_magic_root option ensures that access attempts by root +DON'T ignore deny. Use this for daemon-based stuff, like +telnet/rsh/login. + +

+The even_deny_root_account option is used to ensure that the +root account can become unavailable. Note that magic root +trying to gain root bypasses this, but normal users can be locked out. + +

+The reset option instructs the module to reset count to 0 on +successful entry, even for magic root. The no_reset option is +used to instruct the module to not reset the count on successful +entry. This is the default unless deny exists and the user +attempting access is NOT magic root. + +

+If /var/log/faillog contains a non-zero .fail_max +field for this user then the per_user module argument will +ensure that the module uses this value and not the global +deny=n parameter. + +

+The no_lock_time option is for ensuring that the module does +not use the .fail_locktime field in /var/log/faillog for this +user. + +

+Normally, failed attempts to access root will NOT cause the +root account to become blocked, to prevent denial-of-service: if your +users aren't given shell accounts and root may only login via +su or at the machine console (not +telnet/rsh, etc), this is safe. If you really want +root to be blocked for some given service, use +even_deny_root_account. + + + + diff --git a/Linux-PAM/doc/modules/pam_time.sgml b/Linux-PAM/doc/modules/pam_time.sgml new file mode 100644 index 00000000..785f76c2 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_time.sgml @@ -0,0 +1,166 @@ + + +Time control + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author + +Management groups provided: +account + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Requires a configuration file /etc/security/time.conf + +Network aware: +Through the + +Overview of module + +

+Running a well regulated system occasionally involves restricting +access to certain services in a selective manner. This module offers +some time control for access to services offered by a system. Its +actions are determined with a configuration file. This module can be +configured to deny access to (individual) users based on their name, +the time of day, the day of week, the service they are applying for +and their terminal from which they are making their request. + +Account component + +

+ + +Recognized arguments: + +Description: + +This module bases its actions on the rules listed in its configuration +file: /etc/security/time.conf. Each rule has the following +form, + + +In words, each rule occupies a line, terminated with a newline or the +beginning of a comment; a ` + + +By a logic list we mean a sequence of tokens (associated with the +appropriate !morgan&!root, indicating that this rule +does not apply to the user morgan nor to root; and +tty*&!ttyp*, which indicates that the rule applies only +to console terminals but not pseudoterminals. + + + +Mo Tu We Th Fr Sa Su Wk Wd Al + + +The last two of these being +The time range part is a pair of 24-hour times, + +

+Note, that the given time restriction is only applied when the first +three fields are satisfied by a user's application for service. + +

+For convenience and readability a rule can be extended beyond a single +line with a `\Examples/suggested usage: + +The use of this module is initiated with an entry in the + + +# +# apply pam_time accounting to login requests +# +login account required pam_time.so + + +where, here we are applying the module to the +Some examples of rules that can be placed in the +/etc/security/time.conf configuration file are the following: + + +login ; tty* & !ttyp* ; !root ; !Al0000-2400 +all users except for games ; * ; !waster ; Wd0000-2400 | Wk1800-0800 +games (configured to use Linux-PAM) are only to be accessed out of +working hours. This rule does not apply to the user + +

+Note, currently there is no daemon enforcing the end of a session. +This needs to be remedied. + +

+Poorly formatted rules are logged as errors using + + diff --git a/Linux-PAM/doc/modules/pam_unix.sgml b/Linux-PAM/doc/modules/pam_unix.sgml new file mode 100644 index 00000000..286cd3f8 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_unix.sgml @@ -0,0 +1,288 @@ + + +The Unix Password module + +Synopsis + +

+ + +Module Name: +pam_unix + +Author: + +Maintainer: + +Management groups provided: +account; authentication; password; session + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: + + + +Overview of module + +

+This is the standard Unix authentication module. It uses standard calls +from the system's libraries to retrieve and set account information as +well as authentication. Usually this is obtained from the /etc/passwd +and the /etc/shadow file as well if shadow is enabled. + +Account component + +

+ + +Recognized arguments: +Description: + +The Examples/suggested usage: + +In its accounting mode, this module can be inserted as follows: + + +# +# Ensure users account and password are still active +# +login account required pam_unix.so + + + + + +Authentication component + +

+ + +Recognized arguments: +Description: + +The +The default action of this module is to not permit the user access to +a service if their +When given the argument +The argument, nodelay, can be used to discourage the +authentication component from requesting a delay should the +authentication as a whole fail. The default action is for the module +to request a delay-on-failure of the order of one second. + +

+Remaining arguments, supported by the other functions of this module, +are silently ignored. Other arguments are logged as errors through + +A helper binary, unix_chkpwd, is provided to check the user's +password when it is stored in a read protected database. This binary +is very simple and will only check the password of the user invoking +it. It is called transparently on behalf of the user by the +authenticating component of this module. In this way it is possible +for applications like xlock to work without being setuid-root. + +Examples/suggested usage: + +The correct functionality of this module is dictated by having an +appropriate /etc/nsswitch.conf file, the user +databases specified there dictate the source of the authenticated +user's record. +

+In its authentication mode, this module can be inserted as follows: + + +# +# Authenticate the user +# +login auth required pam_unix.so + + + + + +Password component + +

+ + +Recognized arguments: +Description: + +This part of the +In the case of conventional unix databases (which store the password +encrypted) the +The +The argument +The +The +With the +The /etc/security/opasswd in order to force password change history +and keep the user from alternating between the same password too frequently. + +Examples/suggested usage: + +Standard usage: + + +# +# Change the users password +# +passwd password required pam_unix.so + + + +

+An example of the stacking of this module with respect to the +pluggable password checking module, + +# +# Change the users password +# +passwd password required pam_cracklib.so retry=3 minlen=6 difok=3 +passwd password required pam_unix.so use_authtok nullok md5 + + + + + +Session component + +

+ + +Recognized arguments: + +Description: + +No arguments are recognized by this module component. Its action is +simply to log the username and the service-type to +Examples/suggested usage: + +The use of the session modules is straightforward: + + +# +# session opening and closing +# +login session required pam_unix.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_userdb.sgml b/Linux-PAM/doc/modules/pam_userdb.sgml new file mode 100644 index 00000000..bdbf80b8 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_userdb.sgml @@ -0,0 +1,112 @@ + + +The userdb module + +Synopsis + +

+ + +Module Name: +Author: +Cristian Gafton <gafton@redhat.com> + +Maintainer: +Author. + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Requires Berkeley DB. + +Network aware: + + + +Overview of module + +

+Look up users in a .db database and verify their password against +what is contained in that database. + +Authentication component + +

+ + +Recognized arguments: +Description: + +This module is used to verify a username/password pair against values stored in +a Berkeley DB database. The database is indexed by the username, and the data +fields corresponding to the username keys are the passwords, in unencrypted form, +so caution must be exercised over the access rights to the DB database itself.. + +The module will read the password from the user using the conversation mechanism. If +you are using this module on top of another authetication module (like +The action of the module may be modified from this default by one or +more of the following flags in the /etc/pam.d/<service> file. + + + + + +/etc/foodata +instead of /etc/foodata.db. + + + +Examples/suggested usage: + +This is a normal ftp configuration file (usually placed as /etc/pam.d/ftp +on most systems) that will accept for login users whose username/password pairs are +provided in the /tmp/dbtest.db file: + + + +#%PAM-1.0 +auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed +auth sufficient pam_userdb.so icase db=/tmp/dbtest +auth required pam_pwdb.so shadow nullok try_first_pass +auth required pam_shells.so +account required pam_pwdb.so +session required pam_pwdb.so + + + + + + diff --git a/Linux-PAM/doc/modules/pam_warn.sgml b/Linux-PAM/doc/modules/pam_warn.sgml new file mode 100644 index 00000000..caedf873 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_warn.sgml @@ -0,0 +1,67 @@ + + +Warning logger module + +Synopsis + +

+ + +Module Name: +Author: +Andrew G. Morgan <morgan@kernel.org> + +Maintainer: +Author. + +Management groups provided: +authentication; password + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: + +Network aware: +logs information about the remote user and host (if pam-items are known) + + + +Overview of module + +

+This module is principally for logging information about a +proposed authentication or application to update a password. + +Authentication+Password component + +

+ + +Recognized arguments: + +Description: + +Log the service, terminal, user, remote user and remote host to +Examples/suggested usage: + +an example is provided in the configuration file section . + + + + diff --git a/Linux-PAM/doc/modules/pam_wheel.sgml b/Linux-PAM/doc/modules/pam_wheel.sgml new file mode 100644 index 00000000..cc064120 --- /dev/null +++ b/Linux-PAM/doc/modules/pam_wheel.sgml @@ -0,0 +1,125 @@ + + +The wheel module + +Synopsis + +

+ + +Module Name: +Author: +Cristian Gafton <gafton@redhat.com> + +Maintainer: +Author. + +Management groups provided: +authentication + +Cryptographically sensitive: + +Security rating: + +Clean code base: + +System dependencies: +Requires libpwdb. + +Network aware: + + + +Overview of module + +

+Only permit root access to members of the wheel (Authentication component + +

+ + +Recognized arguments: +Description: + +This module is used to enforce the so-called +The action of the module may be modified from this default by one or +more of the following flags in the /etc/pam.conf file. + + + + + + + + +Examples/suggested usage: + +To restrict access to superuser status to the members of the + + +# +# root gains access by default (rootok), only wheel members can +# become root (wheel) but Unix authenticate non-root applicants. +# +su auth sufficient pam_rootok.so +su auth required pam_wheel.so +su auth required pam_unix_auth.so + + + + + + diff --git a/Linux-PAM/doc/pam_appl.sgml b/Linux-PAM/doc/pam_appl.sgml new file mode 100644 index 00000000..f6d35b4e --- /dev/null +++ b/Linux-PAM/doc/pam_appl.sgml @@ -0,0 +1,1782 @@ + + + + +

+ +The Linux-PAM Application Developers' Guide +<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> +<date>DRAFT v0.76 2001/12/08 +<abstract> +This manual documents what an application developer needs to know +about the <bf>Linux-PAM</bf> library. It describes how an application +might use the <bf>Linux-PAM</bf> library to authenticate users. In +addition it contains a description of the funtions to be found in +<tt/libpam_misc/ library, that can be used in general applications. +Finally, it contains some comments on PAM related security issues for +the application developer. +</abstract> + +<toc> + +<sect>Introduction + +<sect1>Synopsis + +<p> +For general applications that wish to use the services provided by +<bf/Linux-PAM/ the following is a summary of the relevant linking +information: +<tscreen> +<verb> +#include <security/pam_appl.h> + +cc -o application .... -lpam -ldl +</verb> +</tscreen> + +<p> +In addition to <tt/libpam/, there is a library of miscellaneous +functions that make the job of writing <em/PAM-aware/ applications +easier (this library is not covered in the DCE-RFC for PAM and is +specific to the Linux-PAM distribution): +<tscreen> +<verb> +... +#include <security/pam_misc.h> + +cc -o application .... -lpam -lpam_misc -ldl +</verb> +</tscreen> + +<sect1> Description + +<p> +<bf>Linux-PAM</bf> (Pluggable Authentication Modules for Linux) is a +library that enables the local system administrator to choose how +individual applications authenticate users. For an overview of the +<bf>Linux-PAM</bf> library see the <bf/Linux-PAM/ System +Administrators' Guide. + +<p> +It is the purpose of the <bf>Linux-PAM</bf> project to liberate the +development of privilege granting software from the development of +secure and appropriate authentication schemes. This is accomplished +by providing a documented library of functions that an application may +use for all forms of user authentication management. This library +dynamically loads locally configured authentication modules that +actually perform the authentication tasks. + +<p> +From the perspective of an application developer the information +contained in the local configuration of the PAM library should not be +important. Indeed it is intended that an application treat the +functions documented here as a ``black box'' that will deal with all +aspects of user authentication. ``All aspects'' includes user +verification, account management, session initialization/termination +and also the resetting of passwords (<em/authentication tokens/). + +<sect>Overview + +<p> +Most service-giving applications are restricted. In other words, +their service is not available to all and every prospective client. +Instead, the applying client must jump through a number of hoops to +convince the serving application that they are authorized to obtain +service. + +The process of <em/authenticating/ a client is what PAM is designed to +manage. In addition to authentication, PAM provides account +management, credential management, session management and +authentication-token (password changing) management services. It is +important to realize when writing a PAM based application that these +services are provided in a manner that is <bf>transparent</bf> to +the application. That is to say, when the application is written, no +assumptions can be made about <em>how</em> the client will be +authenticated. + +<p> +The process of authentication is performed by the PAM library via a +call to <tt>pam_authenticate()</tt>. The return value of this +function will indicate whether a named client (the <em>user</em>) has +been authenticated. If the PAM library needs to prompt the user for +any information, such as their <em>name</em> or a <em>password</em> +then it will do so. If the PAM library is configured to authenticate +the user using some silent protocol, it will do this too. (This +latter case might be via some hardware interface for example.) + +<p> +It is important to note that the application must leave all decisions +about when to prompt the user at the discretion of the PAM library. + +<p> +The PAM library, however, must work equally well for different styles +of application. Some applications, like the familiar <tt>login</tt> +and <tt>passwd</tt> are terminal based applications, exchanges of +information with the client in these cases is as plain text messages. +Graphically based applications, however, have a more sophisticated +interface. They generally interact with the user via specially +constructed dialogue boxes. Additionally, network based services +require that text messages exchanged with the client are specially +formatted for automated processing: one such example is <tt>ftpd</tt> +which prefixes each exchanged message with a numeric identifier. + +<p> +The presentation of simple requests to a client is thus something very +dependent on the protocol that the serving application will use. In +spite of the fact that PAM demands that it drives the whole +authentication process, it is not possible to leave such protocol +subtleties up to the PAM library. To overcome this potential problem, +the application provides the PAM library with a <em>conversation</em> +function. This function is called from <bf>within</bf> the PAM +library and enables the PAM to directly interact with the client. The +sorts of things that this conversation function must be able to do are +prompt the user with text and/or obtain textual input from the user +for processing by the PAM library. The details of this function are +provided in a later section. + +<p> +For example, the conversation function may be called by the PAM library +with a request to prompt the user for a password. Its job is to +reformat the prompt request into a form that the client will +understand. In the case of <tt>ftpd</tt>, this might involve prefixing +the string with the number <tt>331</tt> and sending the request over +the network to a connected client. The conversation function will +then obtain any reply and, after extracting the typed password, will +return this string of text to the PAM library. Similar concerns need +to be addressed in the case of an X-based graphical server. + +<p> +There are a number of issues that need to be addressed when one is +porting an existing application to become PAM compliant. A section +below has been devoted to this: Porting legacy applications. + +<p> +Besides authentication, PAM provides other forms of management. +Session management is provided with calls to +<tt>pam_open_session()</tt> and <tt>pam_close_session()</tt>. What +these functions actually do is up to the local administrator. But +typically, they could be used to log entry and exit from the system or +for mounting and unmounting the user's home directory. If an +application provides continuous service for a period of time, it +should probably call these functions, first open after the user is +authenticated and then close when the service is terminated. + +<p> +Account management is another area that an application developer +should include with a call to <tt/pam_acct_mgmt()/. This call will +perform checks on the good health of the user's account (has it +expired etc.). One of the things this function may check is whether +the user's authentication token has expired - in such a case the +application may choose to attempt to update it with a call to +<tt/pam_chauthtok()/, although some applications are not suited to +this task (<em>ftp</em> for example) and in this case the application +should deny access to the user. + +<p> +PAM is also capable of setting and deleting the users credentials with +the call <tt>pam_setcred()</tt>. This function should always be +called after the user is authenticated and before service is offered +to the user. By convention, this should be the last call to the PAM +library before the PAM session is opened. What exactly a credential +is, is not well defined. However, some examples are given in the +glossary below. + +<sect>The public interface to <bf>Linux-PAM</bf> + +<p> +Firstly, the relevant include file for the <bf>Linux-PAM</bf> library +is <tt><security/pam_appl.h></tt>. It contains the definitions +for a number of functions. After listing these functions, we collect +some guiding remarks for programmers. + +<sect1>What can be expected by the application + +<p> +Below we document those functions in the <bf/Linux-PAM/ library that +may be called from an application. + +<sect2>Initialization of Linux-PAM +<label id="pam-start-section"> + +<p> +<tscreen> +<verb> +extern int pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh); +</verb> +</tscreen> + +<p> +This is the first of the <bf>Linux-PAM</bf> functions that must be +called by an application. It initializes the interface and reads the +system configuration file, <tt>/etc/pam.conf</tt> (see the +<bf/Linux-PAM/ System Administrators' Guide). Following a successful +return (<tt/PAM_SUCCESS/) the contents of <tt/*pamh/ is a handle that +provides continuity for successive calls to the <bf/Linux-PAM/ +library. The arguments expected by <tt/pam_start/ are as follows: the +<tt/service_name/ of the program, the <tt/user/name of the individual +to be authenticated, a pointer to an application-supplied +<tt/pam_conv/ structure and a pointer to a <tt/pam_handle_t/ +<em/pointer/. + +<p> +The <tt>pam_conv</tt> structure is discussed more fully in the section +<ref id="the-conversation-function" name="below">. The +<tt>pam_handle_t</tt> is a <em>blind</em> structure and the +application should not attempt to probe it directly for information. +Instead the <bf>Linux-PAM</bf> library provides the functions +<tt>pam_set_item</tt> and <tt>pam_get_item</tt>. These functions are +documented below. + +<sect2>Termination of the library +<label id="pam-end-section"> + +<p> +<tscreen> +<verb> +extern int pam_end(pam_handle_t *pamh, int pam_status); +</verb> +</tscreen> + +<p> +This function is the last function an application should call in the +<bf>Linux-PAM</bf> library. Upon return the handle <tt/pamh/ is no +longer valid and all memory associated with it will be invalid (likely +to cause a segmentation fault if accessed). + +<p> +Under normal conditions the argument <tt/pam_status/ has the value +PAM_SUCCESS, but in the event of an unsuccessful application for +service the appropriate <bf/Linux-PAM/ error-return value should be +used here. Note, <tt/pam_end()/ unconditionally shuts down the +authentication stack associated with the <tt/pamh/ handle. The value +taken by <tt/pam_status/ is used as an argument to the module specific +callback functions, <tt/cleanup()/ (see the <bf/Linux-PAM/ <htmlurl +url="pam_modules.html" name="Module Developers' Guide">). In this way, +the module can be given notification of the pass/fail nature of the +tear-down process, and perform any last minute tasks that are +appropriate to the module before it is unlinked. + +<sect2>Setting PAM items +<label id="pam-set-item-section"> + +<p> +<tscreen> +<verb> +extern int pam_set_item(pam_handle_t *pamh, int item_type, + const void *item); +</verb> +</tscreen> + +<p>This function is used to (re)set the value of one of the following +<bf/item_type/s: + +<p><descrip> +<tag><tt/PAM_SERVICE/</tag> + + The service name (which identifies that PAM stack that + <tt/libpam/ will use to authenticate the program). + +<tag><tt/PAM_USER/</tag> + + The username of the entity under who's identity service will + be given. That is, following authentication, <tt/PAM_USER/ + identifies the local entity that gets to use the + service. Note, this value can be mapped from something (eg., + "<tt/anonymous/") to something else (eg. "<tt/guest119/") by + any module in the PAM stack. As such an application should + consult the value of <tt/PAM_USER/ after each call to a + <tt/pam_*()/ function. + +<tag><tt/PAM_USER_PROMPT/</tag> + + The string used when prompting for a user's name. The default + value for this string is ``Please enter username: ''. + +<tag><tt/PAM_TTY/</tag> + + The terminal name: prefixed by <tt>/dev/</tt> if it is a + device file; for graphical, X-based, applications the value + for this item should be the <tt/$DISPLAY/ variable. + +<tag><tt/PAM_RUSER/</tag> + + The requesting entity: user's username for a locally + requesting user or a remote requesting user - generally an + application or module will attempt to supply the value that is + most strongly authenticated (a local account before a remote + one. The level of trust in this value is embodied in the + actual authentication stack associated with the application, + so it is ultimately at the discretion of the system + administrator. It should generally match the current + <tt/PAM_RHOST/ value. That is, "<tt/PAM_RUSER@PAM_RHOST/" + should always identify the requesting user. In some cases, + <tt/PAM_RUSER/ may be NULL. In such situations, it is unclear + who the requesting entity is. + +<tag><tt/PAM_RHOST/</tag> + + The requesting hostname (the hostname of the machine from + which the <tt/PAM_RUSER/ entity is requesting service). That + is "<tt/PAM_RUSER@PAM_RHOST/" does identify the requesting + user. "<tt/luser@localhost/" or "<tt/evil@evilcom.com/" are + valid "<tt/PAM_RUSER@PAM_RHOST/" examples. In some + applications, <tt/PAM_RHOST/ may be NULL. In such situations, + it is unclear where the authentication request is originating + from. + +<tag><tt/PAM_CONV/</tag> + + The conversation structure (see section <ref + id="the-conversation-function" name="below">). + +<tag><tt/PAM_FAIL_DELAY/</tag> A function pointer to redirect + centrally managed failure delays (see section <ref + id="the-failure-delay-function" name="below">). + +</descrip> + +<p> +For all <tt/item_type/s, other than <tt/PAM_CONV/ and +<tt/PAM_FAIL_DELAY/, <tt/item/ is a pointer to a <tt><NUL></tt> +terminated character string. In the case of <tt/PAM_CONV/, <tt/item/ +points to an initialized <tt/pam_conv/ structure (see section <ref +id="the-conversation-function" name="below">). In the case of +<tt/PAM_FAIL_DELAY/, <tt/item/ is a function pointer: <tt/void +(*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)/ (see +section <ref id="the-failure-delay-function" name="below">). + +<p> +A successful call to this function returns <tt/PAM_SUCCESS/. However, +the application should expect at least one the following errors: + +<p> +<descrip> +<tag><tt/PAM_SYSTEM_ERR/</tag> + The <tt/pam_handle_t/ passed as a first argument to this + function was invalid. +<tag><tt/PAM_PERM_DENIED/</tag> + An attempt was made to replace the conversation structure with + a <tt/NULL/ value. +<tag><tt/PAM_BUF_ERR/</tag> + The function ran out of memory making a copy of the item. +<tag><tt/PAM_BAD_ITEM/</tag> + The application attempted to set an undefined or inaccessible + item. +</descrip> + +<sect2>Getting PAM items +<label id="pam-get-item-section"> + +<p> +<tscreen> +<verb> +extern int pam_get_item(const pam_handle_t *pamh, int item_type, + const void **item); +</verb> +</tscreen> + +<p> +This function is used to obtain the value of the indicated +<tt/item_type/. Upon successful return, <tt/*item/ contains a pointer +to the value of the corresponding item. Note, this is a pointer to +the <em/actual/ data and should <em/not/ be <tt/free()/'ed or +over-written! + +<p> +A successful call is signaled by a return value of <tt/PAM_SUCCESS/. +However, the application should expect one of the following errors: + +<p> +<descrip> +<tag><tt/PAM_SYSTEM_ERR/</tag> + The <tt/pam_handle_t/ passed as a first argument to this + function was invalid. +<tag><tt/PAM_PERM_DENIED/</tag> + The value of <tt/item/ was <tt/NULL/. +<tag><tt/PAM_BAD_ITEM/</tag> + The application attempted to set an undefined or inaccessible + item. +</descrip> + +<p> +Note, in the case of an error, the contents of <tt/item/ is not +modified - that is, it retains its pre-call value. One should take +care to initialize this value prior to calling +<tt/pam_get_item()/. Since, if its value - despite the +<tt/pam_get_item()/ function failing - is to be used the consequences +are undefined. + +<sect2>Understanding errors +<label id="pam-strerror-section"> + +<p> +<tscreen> +<verb> +extern const char *pam_strerror(pam_handle_t *pamh, int errnum); +</verb> +</tscreen> + +<p> +This function returns some text describing the <bf>Linux-PAM</bf> +error associated with the argument <tt/errnum/. If the error is not +recognized ``<tt/Unknown Linux-PAM error/'' is returned. + +<sect2>Planning for delays +<label id="the-failure-delay-function"> + +<p> +<tscreen> +<verb> +extern int pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec); +</verb> +</tscreen> + +<p> +This function is offered by <bf/Linux-PAM/ to facilitate time delays +following a failed call to <tt/pam_authenticate()/ and before control +is returned to the application. When using this function the +application programmer should check if it is available with, +<tscreen> +<verb> +#ifdef PAM_FAIL_DELAY + .... +#endif /* PAM_FAIL_DELAY */ +</verb> +</tscreen> + + +<p> +Generally, an application requests that a user is authenticated by +<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or +<tt/pam_chauthtok()/. These functions call each of the <em/stacked/ +authentication modules listed in the relevant <bf/Linux-PAM/ +configuration file. As directed by this file, one of more of the +modules may fail causing the <tt/pam_...()/ call to return an error. +It is desirable for there to also be a pause before the application +continues. The principal reason for such a delay is security: a delay +acts to discourage <em/brute force/ dictionary attacks primarily, but +also helps hinder <em/timed/ (covert channel) attacks. + +<p> +The <tt/pam_fail_delay()/ function provides the mechanism by which an +application or module can suggest a minimum delay (of <tt/micro_sec/ +<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time +requested with this function. Should <tt/pam_authenticate()/ fail, +the failing return to the application is delayed by an amount of time +randomly distributed (by up to 25%) about this longest value. + +<p> +Independent of success, the delay time is reset to its zero default +value when <bf/Linux-PAM/ returns control to the application. + +<p> +For applications written with a single thread that are event driven in +nature, <tt/libpam/ generating this delay may be undesirable. Instead, +the application may want to register the delay in some other way. For +example, in a single threaded server that serves multiple +authentication requests from a single event loop, the application +might want to simply mark a given connection as blocked until an +application timer expires. For this reason, <bf/Linux-PAM/ supplies +the <tt/PAM_FAIL_DELAY/ item. It can be queried and set with +<tt/pam_get_item()/ and <tt/pam_set_item()/ respectively. The value +used to set it should be a function pointer of the following +prototype: + +<tscreen> +<verb> +void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr); +</verb> +</tscreen> + +The arguments being the <tt/retval/ return code of the module stack, +the <tt/usec_delay/ micro-second delay that libpam is requesting and +the <tt/appdata_ptr/ that the application has associated with the +current <tt/pamh/ (<tt/pam_handle_t/). This last value was set by the +application when it called <tt/pam_start/ or explicitly with +<tt/pam_set_item(... , PAM_CONV, ...)/. Note, if <tt/PAM_FAIL_DELAY/ +is unset (or set to <tt/NULL/), then <tt/libpam/ will perform any +delay. + +<sect2>Authenticating the user + +<p> +<tscreen> +<verb> +extern int pam_authenticate(pam_handle_t *pamh, int flags); +</verb> +</tscreen> + +<p> +This function serves as an interface to the authentication mechanisms +of the loaded modules. The single <em/optional/ flag, which may be +logically OR'd with <tt/PAM_SILENT/, takes the following value, + +<p><descrip> + +<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag> + Instruct the authentication modules to return +<tt/PAM_AUTH_ERR/ if the user does not have a registered +authorization token---it is set to <tt/NULL/ in the system database. +</descrip> + +<p> +The value returned by this function is one of the following: + +<p><descrip> + +<tag><tt/PAM_AUTH_ERR/</tag> + The user was not authenticated +<tag><tt/PAM_CRED_INSUFFICIENT/</tag> + For some reason the application does not have sufficient +credentials to authenticate the user. +<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag> + The modules were not able to access the authentication +information. This might be due to a network or hardware failure etc. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The supplied username is not known to the authentication +service +<tag><tt/PAM_MAXTRIES/</tag> + One or more of the authentication modules has reached its +limit of tries authenticating the user. Do not try again. + +</descrip> + +<p> +If one or more of the authentication modules fails to load, for +whatever reason, this function will return <tt/PAM_ABORT/. + +<sect2>Setting user credentials +<label id="pam-setcred-section"> + +<p> +<tscreen> +<verb> +extern int pam_setcred(pam_handle_t *pamh, int flags); +</verb> +</tscreen> + +<p> +This function is used to set the module-specific credentials of the +user. It is usually called after the user has been authenticated, +after the account management function has been called but before a +session has been opened for the user. + +<p> +A credential is something that the user possesses. It is some +property, such as a <em>Kerberos</em> ticket, or a supplementary group +membership that make up the uniqueness of a given user. On a Linux +(or UN*X system) the user's <tt>UID</tt> and <tt>GID</tt>'s are +credentials too. However, it has been decided that these properties +(along with the default supplementary groups of which the user is a +member) are credentials that should be set directly by the application +and not by PAM. + +<p> +This function simply calls the <tt/pam_sm_setcred/ functions of each +of the loaded modules. Valid <tt/flags/, any one of which, may be +logically OR'd with <tt/PAM_SILENT/, are: + +<p><descrip> +<tag><tt/PAM_ESTABLISH_CRED/</tag> + Set the credentials for the authentication service, +<tag><tt/PAM_DELETE_CRED/</tag> + Delete the credentials associated with the authentication service, +<tag><tt/PAM_REINITIALIZE_CRED/</tag> + Reinitialize the user credentials, and +<tag><tt/PAM_REFRESH_CRED/</tag> + Extend the lifetime of the user credentials. +</descrip> + +<p> +A successful return is signalled with <tt/PAM_SUCCESS/. Errors that +are especially relevant to this function are the following: + +<p><descrip> +<tag><tt/PAM_CRED_UNAVAIL/</tag> + A module cannot retrieve the user's credentials. +<tag><tt/PAM_CRED_EXPIRED/</tag> + The user's credentials have expired. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to an authentication module. +<tag><tt/PAM_CRED_ERR/</tag> + A module was unable to set the credentials of the user. +</descrip> + +<sect2>Account management + +<p> +<tscreen> +<verb> +extern int pam_acct_mgmt(pam_handle_t *pamh, int flags); +</verb> +</tscreen> + +<p> +This function is typically called after the user has been +authenticated. It establishes whether the user's account is healthy. +That is to say, whether the user's account is still active and whether +the user is permitted to gain access to the system at this time. +Valid flags, any one of which, may be logically OR'd with +<tt/PAM_SILENT/, and are the same as those applicable to the +<tt/flags/ argument of <tt/pam_authenticate/. + +<p> +This function simply calls the corresponding functions of each of the +loaded modules, as instructed by the configuration file, +<tt>/etc/pam.conf</tt>. + +<p> +The normal response from this function is <tt/PAM_SUCCESS/, however, +specific failures are indicated by the following error returns: + +<descrip> +<tag><tt/PAM_AUTHTOKEN_REQD/</tag> +The user <bf/is/ valid but their authentication token has +<em/expired/. The correct response to this return-value is to require +that the user satisfies the <tt/pam_chauthtok()/ function before +obtaining service. It may not be possible for some applications to do +this. In such cases, the user should be denied access until such time +as they can update their password. + +<tag><tt/PAM_ACCT_EXPIRED/</tag> + The user is no longer permitted to access the system. +<tag><tt/PAM_AUTH_ERR/</tag> + There was an authentication error. + +<tag><tt/PAM_PERM_DENIED/</tag> + The user is not permitted to gain access at this time. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to a module's account management +component. + +</descrip> + +<sect2>Updating authentication tokens +<label id="pam-chauthtok-section"> + +<p> +<tscreen> +<verb> +extern int pam_chauthtok(pam_handle_t *pamh, const int flags); +</verb> +</tscreen> + +<p> +This function is used to change the authentication token for a given +user (as indicated by the state associated with the handle, +<tt/pamh/). The following is a valid but optional flag which may be +logically OR'd with <tt/PAM_SILENT/, + +<descrip> +<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag> + This argument indicates to the modules that the users +authentication token (password) should only be changed if it has +expired. +</descrip> + +<p> +Note, if this argument is not passed, the application requires that +<em/all/ authentication tokens are to be changed. + +<p> +<tt/PAM_SUCCESS/ is the only successful return value, valid +error-returns are: + +<descrip> +<tag><tt/PAM_AUTHTOK_ERR/</tag> + A module was unable to obtain the new authentication token. + +<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag> + A module was unable to obtain the old authentication token. + +<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag> + One or more of the modules was unable to change the +authentication token since it is currently locked. + +<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag> + Authentication token aging has been disabled for at least one +of the modules. + +<tag><tt/PAM_PERM_DENIED/</tag> + Permission denied. + +<tag><tt/PAM_TRY_AGAIN/</tag> + Not all of the modules were in a position to update the +authentication token(s). In such a case none of the user's +authentication tokens are updated. + +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to the authentication token changing +service. + +</descrip> + +<sect2>Session initialization +<label id="pam-open-session-section"> + +<p> +<tscreen> +<verb> +extern int pam_open_session(pam_handle_t *pamh, int flags); +</verb> +</tscreen> + +<p> +This function is used to indicate that an authenticated session has +begun. It is used to inform the modules that the user is currently in +a session. It should be possible for the <bf>Linux-PAM</bf> library +to open a session and close the same session (see section <ref +id="pam-close-session-section" name="below">) from different +applications. + +<p> +Currently, this function simply calls each of the corresponding +functions of the loaded modules. The only valid flag is +<tt/PAM_SILENT/ and this is, of course, <em/optional/. + +<p> +If any of the <em/required/ loaded modules are unable to open a +session for the user, this function will return <tt/PAM_SESSION_ERR/. + +<sect2>Terminating sessions +<label id="pam-close-session-section"> + +<p> +<tscreen> +<verb> +extern int pam_close_session(pam_handle_t *pamh, int flags); +</verb> +</tscreen> + +<p> +This function is used to indicate that an authenticated session has +ended. It is used to inform the modules that the user is exiting a +session. It should be possible for the <bf>Linux-PAM</bf> library to +open a session and close the same session from different applications. + +<p> +This function simply calls each of the corresponding functions of the +loaded modules in the same order that they were invoked with +<tt/pam_open_session()/. The only valid flag is <tt/PAM_SILENT/ and +this is, of course, <em/optional/. + +<p> +If any of the <em/required/ loaded modules are unable to close a +session for the user, this function will return <tt/PAM_SESSION_ERR/. + +<sect2>Setting PAM environment variables +<label id="pam-putenv-section"> + +<p> +The <tt/libpam/ library associates with each PAM-handle (<tt/pamh/), a +set of <it/PAM environment variables/. These variables are intended to +hold the session environment variables that the user will inherit when +the session is granted and the authenticated user obtains access to +the requested service. For example, when <tt/login/ has finally given +the user a shell, the environment (as viewed with the command +<tt/env/) will be what <tt/libpam/ was maintaining as the PAM +environment for that service application. Note, these variables are not +the environment variables of the <tt/login/ application. This is +principally for two reasons: <tt/login/ may want to have an +environment that cannot be seen or manipulated by a user; and +<tt/login/ (or whatever the serving application is) may be maintaining +a number of parallel sessions, via different <tt/pamh/ values, at the +same time and a single environment may not be appropriately shared +between each of these. The PAM environment may contain variables +seeded by the applicant user's client program, for example, and as +such it is not appropriate for one applicant to interfere with the +environment of another applicant. + +<p> +<tscreen> +<verb> +extern int pam_putenv(pam_handle_t *pamh, const char *name_value); +</verb> +</tscreen> + +<p> +This function attempts to (re)set a <bf/Linux-PAM/ environment +variable. The <tt/name_value/ argument is a single <tt/NUL/ terminated +string of one of the following forms: +<descrip> +<tag>``<tt/NAME=value of variable/''</tag> + +In this case the environment variable of the given <tt/NAME/ is set to +the indicated value: ``<tt/value of variable/''. If this variable is +already known, it is overwritten. Otherwise it is added to the +<bf/Linux-PAM/ environment. + +<tag>``<tt/NAME=/''</tag> + +This function sets the variable to an empty value. It is listed +separately to indicate that this is the correct way to achieve such a +setting. + +<tag>``<tt/NAME/''</tag> + +Without an `<tt/=/' the <tt/pam_putenv()/ function will delete the +corresponding variable from the <bf/Linux-PAM/ environment. + +</descrip> + +<p> +Success is indicated with a return value of <tt/PAM_SUCCESS/. Failure +is indicated by one of the following returns: + +<descrip> +<tag><tt/PAM_PERM_DENIED/</tag> + name given is a <tt/NULL/ pointer + +<tag><tt/PAM_BAD_ITEM/</tag> + variable requested (for deletion) is not currently set + +<tag><tt/PAM_ABORT/</tag> + the <bf/Linux-PAM/ handle, <tt/pamh/, is corrupt + +<tag><tt/PAM_BUF_ERR/</tag> + failed to allocate memory when attempting update + +</descrip> + +<sect2>Getting a PAM environment variable +<label id="pam-getenv-section"> + +<p> +<tscreen> +<verb> +extern const char *pam_getenv(pam_handle_t *pamh, const char *name); +</verb> +</tscreen> + +<p> +Obtain the value of the indicated <bf/Linux-PAM/ environment +variable. On error, internal failure or the unavailability of the +given variable (unspecified), this function simply returns <tt/NULL/. + +<sect2>Getting the PAM environment +<label id="pam-getenvlist-section"> + +<p> +<tscreen> +<verb> +extern const char * const *pam_getenvlist(pam_handle_t *pamh); +</verb> +</tscreen> + +<p> +The PAM environment variables (see section <ref +id="pam-putenv-section" name="above">) are a complete set of enviroment +variables that are associated with a PAM-handle (<tt/pamh/). They +represent the contents of the <it/regular/ environment variables of +the authenticated user when service is granted. + +<p> +Th function, <tt>pam_getenvlist()</tt> returns a pointer to a complete, +<tt/malloc()/'d, copy of the PAM environment. It is a pointer to a +duplicated list of environment variables. It should be noted that +this memory will never be <tt/free()'d/ by <tt/libpam/. Once obtained +by a call to <tt/pam_getenvlist()/, <bf>it is the responsibility of +the calling application</bf> to <tt/free()/ this memory. + +<p> +The format of the memory is a <tt/malloc()/'d array of <tt/char */ +pointers, the last element of which is set to <tt/NULL/. Each of the +non-<tt/NULL/ entries in this array point to a <tt/NUL/ terminated and +<tt/malloc()/'d <tt/char/ string of the form: +<tt/"/<it/name/<tt/=/<it/value/<tt/"/. + +<p> +It is by design, and not a coincidence, that the format and contents +of the returned array matches that required for the third argument of +the <tt/execle(3)/ function call. + +<sect1>What is expected of an application + +<sect2>The conversation function +<label id="the-conversation-function"> + +<p> +An application must provide a ``conversation function''. It is used +for direct communication between a loaded module and the application +and will typically provide a means for the module to prompt the user +for a password etc. . The structure, <tt/pam_conv/, is defined by +including <tt><security/pam_appl.h></tt>; to be, + +<p> +<tscreen> +<verb> +struct pam_conv { + int (*conv)(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr); + void *appdata_ptr; +}; +</verb> +</tscreen> + +<p> +It is initialized by the application before it is passed to the +library. The <em/contents/ of this structure are attached to the +<tt/*pamh/ handle. The point of this argument is to provide a +mechanism for any loaded module to interact directly with the +application program. This is why it is called a <em/conversation/ +structure. + +<p> +When a module calls the referenced <tt/conv()/ function, the argument +<tt/*appdata_ptr/ is set to the second element of this structure. + +<p> +The other arguments of a call to <tt/conv()/ concern the information +exchanged by module and application. That is to say, <tt/num_msg/ +holds the length of the array of pointers, <tt/msg/. After a +successful return, the pointer <tt/*resp/ points to an array of +<tt/pam_response/ structures, holding the application supplied text. +Note, <tt/*resp/ is an <tt/struct pam_response/ array and <em/not/ an +array of pointers. + +<p> +The message (from the module to the application) passing structure is +defined by <tt><security/pam_appl.h></tt> as: + +<p> +<tscreen> +<verb> +struct pam_message { + int msg_style; + const char *msg; +}; +</verb> +</tscreen> + +<p> +Valid choices for <tt/msg_style/ are: + +<p><descrip> +<tag><tt/PAM_PROMPT_ECHO_OFF/</tag> + Obtain a string without echoing any text +<tag><tt/PAM_PROMPT_ECHO_ON/</tag> + Obtain a string whilst echoing text +<tag><tt/PAM_ERROR_MSG/</tag> + Display an error +<tag><tt/PAM_TEXT_INFO/</tag> + Display some text. +</descrip> + +<p> +The point of having an array of messages is that it becomes possible +to pass a number of things to the application in a single call from +the module. It can also be convenient for the application that related +things come at once: a windows based application can then present a +single form with many messages/prompts on at once. + +<p> +In passing, it is worth noting that there is a descrepency between the +way Linux-PAM handles the <tt/const struct pam_message **msg/ +conversation function argument from the way that Solaris' PAM (and +derivitives, known to include HP/UX, <em/are there others?/) +does. Linux-PAM interprets the <tt/msg/ argument as entirely +equivalent to the following prototype <tt/const struct pam_message +*msg[]/ (which, in spirit, is consistent with the commonly used +prototypes for <tt/argv/ argument to the familiar <tt/main()/ +function: <tt/char **argv/; and <tt/char *argv[]/). Said another way +Linux-PAM interprets the <tt/msg/ argument as a pointer to an array of +<tt/num_meg/ read only 'struct pam_message' <em/pointers/. Solaris' +PAM implementation interprets this argument as a pointer to a pointer +to an array of <tt/num_meg/ <tt/pam_message/ structures. Fortunately, +perhaps, for most module/application developers when <tt/num_msg/ has +a value of one these two definitions are entirely +equivalent. Unfortunately, casually raising this number to two has led +to unanticipated compatibility problems. + +<p> +For what its worth the two known module writer work-arounds for trying +to maintain source level compatibility with both PAM implementations +are: +<itemize> +<item> never call the conversation function with <tt/num_msg/ greater +than one. +<item> set up <tt/msg/ as doubly referenced so both types of +conversation function can find the messages. That is, make +<p><tscreen> +<verb> +msg[n] = & (( *msg )[n]) +</verb> +</tscreen> +</itemize> +<p> +The response (from the application to the module) passing structure is +defined by including <tt><security/pam_appl.h></tt> as: + +<p><tscreen><verb> +struct pam_response { + char *resp; + int resp_retcode; +}; +</verb></tscreen> + +<p> +Currently, there are no definitions for <tt/resp_retcode/ values; the +normal value is <tt/0/. + +<p> +Prior to the 0.59 release of Linux-PAM, the length of the returned +<tt/pam_response/ array was equal to the number of <em/prompts/ (types +<tt/PAM_PROMPT_ECHO_OFF/ and <tt/PAM_PROMPT_ECHO_ON/) in the +<tt/pam_message/ array with which the conversation function was +called. This meant that it was not always necessary for the module to +<tt/free(3)/ the responses if the conversation function was only used +to display some text. + +<p> +Post Linux-PAM-0.59. The number of responses is always equal to the +<tt/num_msg/ conversation function argument. This is slightly easier +to program but does require that the response array is <tt/free(3)/'d +after every call to the conversation function. The index of the +responses corresponds directly to the prompt index in the +<tt/pam_message/ array. + +<p> +The maximum length of the <tt/pam_msg.msg/ and <tt/pam_response.resp/ +character strings is <tt/PAM_MAX_MSG_SIZE/. (This is not enforced by +Linux-PAM.) + +<p> +<tt/PAM_SUCCESS/ is the expected return value of this +function. However, should an error occur the application should not +set <tt/*resp/ but simply return <tt/PAM_CONV_ERR/. + +<p> +Note, if an application wishes to use two conversation functions, it +should activate the second with a call to <tt/pam_set_item()/. + +<p> +<bf>Notes:</bf> New item types are being added to the conversation +protocol. Currently Linux-PAM supports: <tt>PAM_BINARY_PROMPT</tt> +and <tt>PAM_BINARY_MSG</tt>. These two are intended for server-client +hidden information exchange and may be used as an interface for +maching-machine authentication. + +<sect1>Programming notes + +<p> +Note, all of the authentication service function calls accept the +token <tt/PAM_SILENT/, which instructs the modules to not send +messages to the application. This token can be logically OR'd with any +one of the permitted tokens specific to the individual function calls. +<tt/PAM_SILENT/ does not override the prompting of the user for +passwords etc., it only stops informative messages from being +generated. + +<sect>Security issues of <bf>Linux-PAM</bf> + +<p> +PAM, from the perspective of an application, is a convenient API for +authenticating users. PAM modules generally have no increased +privilege over that possessed by the application that is making use of +it. For this reason, the application must take ultimate responsibility +for protecting the environment in which PAM operates. + +<p> +A poorly (or maliciously) written application can defeat any +<bf/Linux-PAM/ module's authentication mechanisms by simply ignoring +it's return values. It is the applications task and responsibility to +grant privileges and access to services. The <bf/Linux-PAM/ library +simply assumes the responsibility of <em/authenticating/ the user; +ascertaining that the user <em/is/ who they say they are. Care should +be taken to anticipate all of the documented behavior of the +<bf/Linux-PAM/ library functions. A failure to do this will most +certainly lead to a future security breach. + +<sect1>Care about standard library calls + +<p> +In general, writers of authorization-granting applications should +assume that each module is likely to call any or <em/all/ `libc' +functions. For `libc' functions that return pointers to +static/dynamically allocated structures (ie. the library allocates the +memory and the user is not expected to `<tt/free()/' it) any module +call to this function is likely to corrupt a pointer previously +obtained by the application. The application programmer should either +re-call such a `libc' function after a call to the <bf/Linux-PAM/ +library, or copy the structure contents to some safe area of memory +before passing control to the <bf/Linux-PAM/ library. + +<p> +Two important function classes that fall into this category are +<tt>getpwnam(3)</tt> and <tt>syslog(3)</tt>. + +<sect1>Choice of a service name + +<p> +When picking the <em/service-name/ that corresponds to the first entry +in the <bf/Linux-PAM/ configuration file, the application programmer +should <bf/avoid/ the temptation of choosing something related to +<tt/argv[0]/. It is a trivial matter for any user to invoke any +application on a system under a different name and this should not be +permitted to cause a security breach. + +<p> +In general, this is always the right advice if the program is setuid, +or otherwise more privileged than the user that invokes it. In some +cases, avoiding this advice is convenient, but as an author of such an +application, you should consider well the ways in which your program +will be installed and used. (Its often the case that programs are not +intended to be setuid, but end up being installed that way for +convenience. If your program falls into this category, don't fall into +the trap of making this mistake.) + +<p> +To invoke some <tt/target/ application by another name, the user may +symbolically link the target application with the desired name. To be +precise all the user need do is, +<tscreen> +<verb> +ln -s /target/application ./preferred_name +</verb> +</tscreen> +and then <em/run/ <tt>./preferred_name</tt> + +<p> +By studying the <bf/Linux-PAM/ configuration file(s), an attacker can +choose the <tt/preferred_name/ to be that of a service enjoying +minimal protection; for example a game which uses <bf/Linux-PAM/ to +restrict access to certain hours of the day. If the service-name were +to be linked to the filename under which the service was invoked, it +is clear that the user is effectively in the position of dictating +which authentication scheme the service uses. Needless to say, this +is not a secure situation. + +<p> +The conclusion is that the application developer should carefully +define the service-name of an application. The safest thing is to make +it a single hard-wired name. + +<sect1>The conversation function + +<p> +Care should be taken to ensure that the <tt/conv()/ function is +robust. Such a function is provided in the library <tt/libpam_misc/ +(see <ref id="libpam-misc-section" name="below">). + +<sect1>The identity of the user + +<p> +The <bf/Linux-PAM/ modules will need to determine the identity of the +user who requests a service, and the identity of the user who grants +the service. These two users will seldom be the same. Indeed there +is generally a third user identity to be considered, the new (assumed) +identity of the user once the service is granted. + +<p> +The need for keeping tabs on these identities is clearly an issue of +security. One convention that is actively used by some modules is +that the identity of the user requesting a service should be the +current <tt/uid/ (userid) of the running process; the identity of the +privilege granting user is the <tt/euid/ (effective userid) of the +running process; the identity of the user, under whose name the +service will be executed, is given by the contents of the +<tt/PAM_USER/ <tt/pam_get_item(3)/. Note, modules can change the +values of <tt/PAM_USER/ and <tt/PAM_RUSER/ during any of the +<tt/pam_*()/ library calls. For this reason, the application should +take care to use the <tt/pam_get_item()/ every time it wishes to +establish who the authenticated user is (or will currently be). + +<p> +For network-serving databases and other applications that provide +their own security model (independent of the OS kernel) the above +scheme is insufficient to identify the requesting user. + +<p> +A more portable solution to storing the identity of the requesting +user is to use the <tt/PAM_RUSER/ <tt/pam_get_item(3)/. The +application should supply this value before attempting to authenticate +the user with <tt/pam_authenticate()/. How well this name can be +trusted will ultimately be at the discretion of the local +administrator (who configures PAM for your application) and a selected +module may attempt to override the value where it can obtain more +reliable data. If an application is unable to determine the identity +of the requesting entity/user, it should not call <tt/pam_set_item(3)/ +to set <tt/PAM_RUSER/. + +<p> +In addition to the <tt/PAM_RUSER/ item, the application should supply +the <tt/PAM_RHOST/ (<em/requesting host/) item. As a general rule, the +following convention for its value can be assumed: <tt/<unset>/ += unknown; <tt/localhost/ = invoked directly from the local system; +<em/other.place.xyz/ = some component of the user's connection +originates from this remote/requesting host. At present, PAM has no +established convention for indicating whether the application supports +a trusted path to communication from this host. + +<sect1>Sufficient resources + +<p> +Care should be taken to ensure that the proper execution of an +application is not compromised by a lack of system resources. If an +application is unable to open sufficient files to perform its service, +it should fail gracefully, or request additional resources. +Specifically, the quantities manipulated by the <tt/setrlimit(2)/ +family of commands should be taken into consideration. + +<p> +This is also true of conversation prompts. The application should not +accept prompts of arbitrary length with out checking for resource +allocation failure and dealing with such extreme conditions gracefully +and in a mannor that preserves the PAM API. Such tolerance may be +especially important when attempting to track a malicious adversary. + +<sect>A library of miscellaneous helper functions +<label id="libpam-misc-section"> + +<p> +To aid the work of the application developer a library of +miscellaneous functions is provided. It is called <tt/libpam_misc/, +and contains functions for allocating memory (securely), a text based +conversation function, and routines for enhancing the standard +PAM-environment variable support. + +<sect1>Requirements + +<p> +The functions, structures and macros, made available by this library +can be defined by including <tt><security/pam_misc.h></tt>. It +should be noted that this library is specific to <bf/Linux-PAM/ and is +not referred to in the defining DCE-RFC (see <ref id="bibliography" +name="the bibliography">) below. + +<sect1>Macros supplied + +<sect2>Safe duplication of strings + +<p> +<tscreen> +<verb> +x_strdup(const char *s) +</verb> +</tscreen> + +<p> +This macro is a replacement for the <tt/xstrdup()/ function that was +present in earlier versions of the library and which clashed horribly +with a number of applications. It returns a duplicate copy of the +<tt/NUL/ terminated string, <tt/s/. <tt/NULL/ is returned if there is +insufficient memory available for the duplicate or if <tt/s/ is +<tt/NULL/ to begin with. + +<sect1>Functions supplied + +<sect2>A text based conversation function + +<p> +<tscreen> +<verb> +extern int misc_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr); +</verb> +</tscreen> + +<p> +This is a function that will prompt the user with the appropriate +comments and obtain the appropriate inputs as directed by +authentication modules. + +<p> +In addition to simply slotting into the appropriate <tt/struct +pam_conv/, this function provides some time-out facilities. The +function exports five variables that can be used by an application +programmer to limit the amount of time this conversation function will +spend waiting for the user to type something. + +<p> +The five variables are as follows: +<descrip> +<tag><tt>extern time_t pam_misc_conv_warn_time;</tt></tag> + +This variable contains the <em/time/ (as returned by <tt/time()/) that +the user should be first warned that the clock is ticking. By default +it has the value <tt/0/, which indicates that no such warning will be +given. The application may set its value to sometime in the future, +but this should be done prior to passing control to the <bf/Linux-PAM/ +library. + +<tag><tt>extern const char *pam_misc_conv_warn_line;</tt></tag> + +Used in conjuction with <tt/pam_misc_conv_warn_time/, this variable is +a pointer to the string that will be displayed when it becomes time to +warn the user that the timeout is approaching. Its default value is +``..\a.Time is running out...\n'', but this can be changed +by the application prior to passing control to <bf/Linux-PAM/. + +<tag><tt>extern time_t pam_misc_conv_die_time;</tt></tag> + +This variable contains the <em/time/ (as returned by <tt/time()/) that +the conversation will time out. By default it has the value <tt/0/, +which indicates that the conversation function will not timeout. The +application may set its value to sometime in the future, this should +be done prior to passing control to the <bf/Linux-PAM/ library. + +<tag><tt>extern const char *pam_misc_conv_die_line;</tt></tag> + +Used in conjuction with <tt/pam_misc_conv_die_time/, this variable is +a pointer to the string that will be displayed when the conversation +times out. Its default value is ``..\a.Sorry, your time is +up!\n'', but this can be changed by the application prior to +passing control to <bf/Linux-PAM/. + +<tag><tt>extern int pam_misc_conv_died;</tt></tag> + +Following a return from the <bf/Linux-PAM/ libraray, the value of this +variable indicates whether the conversation has timed out. A value of +<tt/1/ indicates the time-out occurred. + +</descrip> + +<p> +The following two function pointers are available for supporting binary +prompts in the conversation function. They are optimized for the +current incarnation of the <tt/libpamc/ library and are subject to +change. +<descrip> +<tag><tt>extern int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t +*prompt_p);</tt></tag> + +This function pointer is initialized to <tt/NULL/ but can be filled +with a function that provides machine-machine (hidden) message +exchange. It is intended for use with hidden authentication protocols +such as RSA or Diffie-Hellman key exchanges. (This is still under +development.) + +<tag><tt>extern int (*pam_binary_handler_free)(void *appdata, +pamc_bp_t *delete_me);</tt></tag> + +This function pointer is initialized to <tt/PAM_BP_RENEW(delete_me, 0, +0)/, but can be redefined as desired by the application. + +</descrip> + +<sect2>Transcribing an environment to that of Linux-PAM +<p> +<tscreen> +<verb> +extern int pam_misc_paste_env(pam_handle_t *pamh, + const char * const * user_env); +</verb> +</tscreen> + +This function takes the supplied list of environment pointers and +<em/uploads/ its contents to the <bf/Linux-PAM/ environment. Success +is indicated by <tt/PAM_SUCCESS/. + +<sect2>Liberating a locally saved environment +<p> +<tscreen> +<verb> +extern char **pam_misc_drop_env(char **env); +</verb> +</tscreen> + +This function is defined to complement the <tt/pam_getenvlist()/ +function. It liberates the memory associated with <tt/env/, +<em/overwriting/ with <tt/0/ all memory before <tt/free()/ing it. + +<sect2>BSD like Linux-PAM environment variable setting +<p> +<tscreen> +<verb> +extern int pam_misc_setenv(pam_handle_t *pamh, const char *name, + const char *value, int readonly); +</verb> +</tscreen> + +This function performs a task equivalent to <tt/pam_putenv()/, its +syntax is, however, more like the BSD style function; <tt/setenv()/. +The <tt/name/ and <tt/value/ are concatenated with an ``<tt/=/'' to +form a <tt/name_value/ and passed to <tt/pam_putenv()/. If, however, +the <bf/Linux-PAM/ variable is already set, the replacement will only +be applied if the last argument, <tt/readonly/, is zero. + +<sect>Porting legacy applications + +<p> +The following is extracted from an email. I'll tidy it up later. + +<p> +The point of PAM is that the application is not supposed to have any +idea how the attached authentication modules will choose to +authenticate the user. So all they can do is provide a conversation +function that will talk directly to the user(client) on the modules' +behalf. + +<p> +Consider the case that you plug a retinal scanner into the login +program. In this situation the user would be prompted: "please look +into the scanner". No username or password would be needed - all this +information could be deduced from the scan and a database lookup. The +point is that the retinal scanner is an ideal task for a "module". + +<p> +While it is true that a pop-daemon program is designed with the POP +protocol in mind and no-one ever considered attaching a retinal +scanner to it, it is also the case that the "clean" PAM'ification of +such a daemon would allow for the possibility of a scanner module +being be attached to it. The point being that the "standard" +pop-authentication protocol(s) [which will be needed to satisfy +inflexible/legacy clients] would be supported by inserting an +appropriate pam_qpopper module(s). However, having rewritten popd +once in this way any new protocols can be implemented in-situ. + +<p> +One simple test of a ported application would be to insert the +<tt/pam_permit/ module and see if the application demands you type a +password... In such a case, <tt/xlock/ would fail to lock the +terminal - or would at best be a screen-saver, ftp would give password +free access to all etc.. Neither of these is a very secure thing to +do, but they do illustrate how much flexibility PAM puts in the hands +of the local admin. + +<p> +The key issue, in doing things correctly, is identifying what is part +of the authentication procedure (how many passwords etc..) the +exchange protocol (prefixes to prompts etc., numbers like 331 in the +case of ftpd) and what is part of the service that the application +delivers. PAM really needs to have total control in the +authentication "procedure", the conversation function should only +deal with reformatting user prompts and extracting responses from raw +input. + +<sect>Glossary of PAM related terms + +<p> +The following are a list of terms used within this document. + +<p> +<descrip> + +<tag>Authentication token</tag> +Generally, this is a password. However, a user can authenticate +him/herself in a variety of ways. Updating the user's authentication +token thus corresponds to <em>refreshing</em> the object they use to +authenticate themself with the system. The word password is avoided +to keep open the possibility that the authentication involves a +retinal scan or other non-textual mode of challenge/response. + +<tag>Credentials</tag> +Having successfully authenticated the user, PAM is able to establish +certain characteristics/attributes of the user. These are termed +<em>credentials</em>. Examples of which are group memberships to +perform privileged tasks with, and <em>tickets</em> in the form of +environment variables etc. . Some user-credentials, such as the +user's UID and GID (plus default group memberships) are not deemed to +be PAM-credentials. It is the responsibility of the application to +grant these directly. + +</descrip> + +<sect>An example application + +<p> +To get a flavor of the way a <tt/Linux-PAM/ application is written we +include the following example. It prompts the user for their password +and indicates whether their account is valid on the standard output, +its return code also indicates the success (<tt/0/ for success; <tt/1/ +for failure). + +<p> +<tscreen> +<verb> +/* + This program was contributed by Shane Watts + [modifications by AGM] + + You need to add the following (or equivalent) to the /etc/pam.conf file. + # check authorization + check_user auth required /usr/lib/security/pam_unix_auth.so + check_user account required /usr/lib/security/pam_unix_acct.so + */ + +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <stdio.h> + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +int main(int argc, char *argv[]) +{ + pam_handle_t *pamh=NULL; + int retval; + const char *user="nobody"; + + if(argc == 2) { + user = argv[1]; + } + + if(argc > 2) { + fprintf(stderr, "Usage: check_user [username]\n"); + exit(1); + } + + retval = pam_start("check_user", user, &ero;conv, &ero;pamh); + + if (retval == PAM_SUCCESS) + retval = pam_authenticate(pamh, 0); /* is user really user? */ + + if (retval == PAM_SUCCESS) + retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ + + /* This is where we have been authorized or not. */ + + if (retval == PAM_SUCCESS) { + fprintf(stdout, "Authenticated\n"); + } else { + fprintf(stdout, "Not Authenticated\n"); + } + + if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ + pamh = NULL; + fprintf(stderr, "check_user: failed to release authenticator\n"); + exit(1); + } + + return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ +} +</verb> +</tscreen> + +<sect>Files + +<p><descrip> + +<tag><tt>/usr/include/security/pam_appl.h</tt></tag> + +header file for <bf/Linux-PAM/ applications interface + +<tag><tt>/usr/include/security/pam_misc.h</tt></tag> + +header file for useful library functions for making applications +easier to write + +<tag><tt>/usr/lib/libpam.so.*</tt></tag> + +the shared library providing applications with access to +<bf/Linux-PAM/. + +<tag><tt>/etc/pam.conf</tt></tag> + +the <bf/Linux-PAM/ configuration file. + +<tag><tt>/usr/lib/security/pam_*.so</tt></tag> + +the primary location for <bf/Linux-PAM/ dynamically loadable object +files; the modules. + +</descrip> + +<sect>See also +<label id="bibliography"> + +<p><itemize> + +<item>The <bf/Linux-PAM/ +<htmlurl url="pam.html" name="System Administrators' Guide">. + +<item>The <bf/Linux-PAM/ +<htmlurl url="pam_modules.html" name="Module Writers' Guide">. + +<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH +PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request +For Comments 86.0, October 1995. + +</itemize> + +<sect>Notes + +<p> +I intend to put development comments here... like ``at the moment +this isn't actually supported''. At release time what ever is in +this section will be placed in the Bugs section below! :) + +<p> +<itemize> + +<item> <tt/pam_strerror()/ should be internationalized.... + +<item> +Note, the <tt/resp_retcode/ of struct <tt/pam_message/, has no +purpose at the moment. Ideas/suggestions welcome! + +<item> more security issues are required.... + +</itemize> + +<sect>Author/acknowledgments + +<p> +This document was written by Andrew G. Morgan +(morgan@kernel.org) with many contributions from +<!-- insert credits here --> +<!-- + an sgml list of people to credit for their contributions to Linux-PAM + $Id: pam_appl.sgml,v 1.1.1.2 2002/09/15 20:08:24 hartmans Exp $ + --> +Chris Adams, +Peter Allgeyer, +Tim Baverstock, +Tim Berger, +Craig S. Bell, +Derrick J. Brashear, +Ben Buxton, +Seth Chaiklin, +Oliver Crow, +Chris Dent, +Marc Ewing, +Cristian Gafton, +Emmanuel Galanos, +Brad M. Garcia, +Eric Hester, +Roger Hu, +Eric Jacksch, +Michael K. Johnson, +David Kinchlea, +Olaf Kirch, +Marcin Korzonek, +Stephen Langasek, +Nicolai Langfeldt, +Elliot Lee, +Luke Kenneth Casson Leighton, +Al Longyear, +Ingo Luetkebohle, +Marek Michalkiewicz, +Robert Milkowski, +Aleph One, +Martin Pool, +Sean Reifschneider, +Jan Rekorajski, +Erik Troan, +Theodore Ts'o, +Jeff Uphoff, +Myles Uyema, +Savochkin Andrey Vladimirovich, +Ronald Wahl, +David Wood, +John Wilmes, +Joseph S. D. Yao +and +Alex O. Yuriev. + +<p> +Thanks are also due to Sun Microsystems, especially to Vipin Samar and +Charlie Lai for their advice. At an early stage in the development of +<bf/Linux-PAM/, Sun graciously made the documentation for their +implementation of PAM available. This act greatly accelerated the +development of <bf/Linux-PAM/. + +<sect>Bugs/omissions + +<p> +This manual is hopelessly unfinished. Only a partial list of people is +credited for all the good work they have done. + +<sect>Copyright information for this document + +<p> +Copyright (c) Andrew G. Morgan 1996-9,2000-1. All rights reserved. +<newline> +Email: <tt><morgan@kernel.org></tt> + +<p> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +<p> +<itemize> + +<item> +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +<item> +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +<item> +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +</itemize> + +<p> +<bf/Alternatively/, this product may be distributed under the terms of +the GNU General Public License (GPL), in which case the provisions of +the GNU GPL are required <bf/instead of/ the above restrictions. +(This clause is necessary due to a potential bad interaction between +the GNU GPL and the restrictions contained in a BSD-style copyright.) + +<p> +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +<p> +<tt>$Id: pam_appl.sgml,v 1.1.1.2 2002/09/15 20:08:24 hartmans Exp $</tt> + +</article> diff --git a/Linux-PAM/doc/pam_modules.sgml b/Linux-PAM/doc/pam_modules.sgml new file mode 100644 index 00000000..c67dd448 --- /dev/null +++ b/Linux-PAM/doc/pam_modules.sgml @@ -0,0 +1,1505 @@ +<!doctype linuxdoc system> + +<!-- + + $Id: pam_modules.sgml,v 1.1.1.2 2002/09/15 20:08:25 hartmans Exp $ + + Copyright (c) Andrew G. Morgan 1996-2001. All rights reserved. + + ** some sections, in this document, were contributed by other + ** authors. They carry individual copyrights. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License, in which case the provisions of the GNU +GPL are required INSTEAD OF the above restrictions. (This clause is +necessary due to a potential bad interaction between the GNU GPL and +the restrictions contained in a BSD-style copyright.) + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + + --> + +<article> + +<title>The Linux-PAM Module Writers' Guide +<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> +<date>DRAFT v0.76 2002/05/09 +<abstract> +This manual documents what a programmer needs to know in order to +write a module that conforms to the <bf/Linux-PAM/ standard. It also +discusses some security issues from the point of view of the module +programmer. +</abstract> + +<toc> + +<sect>Introduction + +<sect1> Synopsis +<p> +<tscreen> +<verb> +#include <security/pam_modules.h> + +gcc -fPIC -c pam_module-name.c +ld -x --shared -o pam_module-name.so pam_module-name.o +</verb> +</tscreen> + +<sect1> Description + +<p> +<bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a +library that enables the local system administrator to choose how +individual applications authenticate users. For an overview of the +<bf/Linux-PAM/ library see the <bf/Linux-PAM/ System Administrators' +Guide. + +<p> +A <bf/Linux-PAM/ module is a single executable binary file that can be +loaded by the <bf/Linux-PAM/ interface library. This PAM library is +configured locally with a system file, <tt>/etc/pam.conf</tt>, to +authenticate a user request via the locally available authentication +modules. The modules themselves will usually be located in the +directory <tt>/usr/lib/security</tt> and take the form of dynamically +loadable object files (see dlopen(3)). Alternatively, the modules can +be statically linked into the <bf/Linux-PAM/ library; this is mostly to +allow <bf/Linux-PAM/ to be used on platforms without dynamic linking +available, but the two forms can be used together. It is the +<bf/Linux-PAM/ interface that is called by an application and it is +the responsibility of the library to locate, load and call the +appropriate functions in a <bf/Linux-PAM/-module. + +<p> +Except for the immediate purpose of interacting with the user +(entering a password etc..) the module should never call the +application directly. This exception requires a "conversation +mechanism" which is documented below. + +<sect>What can be expected by the module + +<p> +Here we list the interface that the conventions that all +<bf/Linux-PAM/ modules must adhere to. + +<sect1>Getting and setting <tt/PAM_ITEM/s and <em/data/ + +<p> +First, we cover what the module should expect from the <bf/Linux-PAM/ +library and a <bf/Linux-PAM/ <em/aware/ application. Essesntially this +is the <tt/libpam.*/ library. + +<sect2> +Setting data + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_set_data(pam_handle_t *pamh, + const char *module_data_name, + void *data, + void (*cleanup)(pam_handle_t *pamh, + void *data, int error_status) ); +</verb> +</tscreen> + +<p> +The modules may be dynamically loadable objects. In general such files +should not contain <tt/static/ variables. This and the subsequent +function provide a mechanism for a module to associate some data with +the handle <tt/pamh/. Typically a module will call the +<tt/pam_set_data()/ function to register some data under a (hopefully) +unique <tt/module_data_name/. The data is available for use by other +modules too but <em/not/ by an application. + +<p> +The function <tt/cleanup()/ is associated with the <tt/data/ and, if +non-<tt/NULL/, it is called when this data is over-written or +following a call to <tt/pam_end()/ (see the Linux-PAM Application +Developers' Guide). + +<p> +The <tt/error_status/ argument is used to indicate to the module the +sort of action it is to take in cleaning this data item. As an +example, Kerberos creates a ticket file during the authentication +phase, this file might be associated with a data item. When +<tt/pam_end()/ is called by the module, the <tt/error_status/ +carries the return value of the <tt/pam_authenticate()/ or other +<tt/libpam/ function as appropriate. Based on this value the Kerberos +module may choose to delete the ticket file (<em/authentication +failure/) or leave it in place. + +<p> +The <tt/error_status/ may have been logically OR'd with either of the +following two values: + +<p> +<descrip> +<tag><tt/PAM_DATA_REPLACE/</tag> + When a data item is being replaced (through a second call to +<tt/pam_set_data()/) this mask is used. Otherwise, the call is assumed +to be from <tt/pam_end()/. + +<tag><tt/PAM_DATA_SILENT/</tag> + Which indicates that the process would prefer to perform the +<tt/cleanup()/ quietly. That is, discourages logging/messages to the +user. + +</descrip> + + +<sect2> +Getting data + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_data(const pam_handle_t *pamh, + const char *module_data_name, + const void **data); +</verb> +</tscreen> + +<p> +This function together with the previous one provides a method of +associating module-specific data with the handle <tt/pamh/. A +successful call to <tt/pam_get_data/ will result in <tt/*data/ +pointing to the data associated with the <tt/module_data_name/. Note, +this data is <em/not/ a copy and should be treated as <em/constant/ +by the module. + +<p> +Note, if there is an entry but it has the value <tt/NULL/, then this +call returns <tt/PAM_NO_MODULE_DATA/. + +<sect2> +Setting items + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_set_item(pam_handle_t *pamh, + int item_type, + const void *item); +</verb> +</tscreen> + +<p> +This function is used to (re)set the value of one of the +<tt/item_type/s. The reader is urged to read the entry for this +function in the <bf/Linux-PAM/ application developers' manual. + +<p> +In addition to the <tt/item/s listed there, the module can set the +following two <tt/item_type/s: + +<p> +<descrip> +<tag><tt/PAM_AUTHTOK/</tag> + +The authentication token (often a password). This token should be +ignored by all module functions besides <tt/pam_sm_authenticate()/ and +<tt/pam_sm_chauthtok()/. In the former function it is used to pass the +most recent authentication token from one stacked module to +another. In the latter function the token is used for another +purpose. It contains the currently active authentication token. + +<tag><tt/PAM_OLDAUTHTOK/</tag> + +The old authentication token. This token should be ignored by all +module functions except <tt/pam_sm_chauthtok()/. + +</descrip> + +<p> +Both of these items are reset before returning to the application. +When resetting these items, the <bf/Linux-PAM/ library first writes +<tt/0/'s to the current tokens and then <tt/free()/'s the associated +memory. + +<p> +The return values for this function are listed in the +<bf>Linux-PAM</bf> Application Developers' Guide. + +<sect2> +Getting items + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_item(const pam_handle_t *pamh, + int item_type, + const void **item); +</verb> +</tscreen> + +<p> +This function is used to obtain the value of the specified +<tt/item_type/. It is better documented in the <bf/Linux-PAM/ +Application Developers' Guide. However, there are three things worth +stressing here: +<itemize> + +<item> +Generally, if the module wishes to obtain the name of the user, it +should not use this function, but instead perform a call to +<tt/pam_get_user()/ (see section <ref id="pam-get-user" +name="below">). + +<item> +The module is additionally privileged to read the authentication +tokens, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/ (see the section +above on <tt/pam_set_data()/). + +<item> +The module should <em/not/ <tt/free()/ or alter the data pointed to by +<tt/*item/ after a successful return from <tt/pam_get_item()/. This +pointer points directly at the data contained within the <tt/*pamh/ +structure. Should a module require that a change is made to the this +<tt/ITEM/ it should make the appropriate call to <tt/pam_set_item()/. +</itemize> + +<sect2>The <em/conversation/ mechanism + +<p> +Following the call <tt>pam_get_item(pamh,PAM_CONV,&item)</tt>, the +pointer <tt/item/ points to a structure containing an a pointer to a +<em/conversation/-function that provides limited but direct access to +the application. The purpose of this function is to allow the module +to prompt the user for their password and pass other information in a +manner consistent with the application. For example, an X-windows +based program might pop up a dialog box to report a login +failure. Just as the application should not be concerned with the +method of authentication, so the module should not dictate the manner +in which input (output) is obtained from (presented to) to the user. + +<p> +<bf>The reader is strongly urged to read the more complete description of +the <tt/pam_conv/ structure, written from the perspective of the +application developer, in the <bf/Linux-PAM/ Application Developers' +Guide.</bf> + +<p> +The return values for this function are listed in the +<bf>Linux-PAM</bf> Application Developers' Guide. + +<p> +The <tt/pam_response/ structure returned after a call to the +<tt/pam_conv/ function must be <tt/free()/'d by the module. Since the +call to the conversation function originates from the module, it is +clear that this <tt/pam_response/ structure could be either statically +or dynamically (using <tt/malloc()/ etc.) allocated within the +application. Repeated calls to the conversation function would likely +overwrite static memory, so it is required that for a successful +return from the conversation function the memory for the response +structure is dynamically allocated by the application with one of the +<tt/malloc()/ family of commands and <em/must/ be <tt/free()/'d by the +module. + +<p> +If the <tt/pam_conv/ mechanism is used to enter authentication tokens, +the module should either pass the result to the <tt/pam_set_item()/ +library function, or copy it itself. In such a case, once the token +has been stored (by one of these methods or another one), the memory +returned by the application should be overwritten with <tt/0/'s, and +then <tt/free()/'d. + +There is a handy macro <tt/_pam_drop_reply()/ to be found in +<tt><security/_pam_macros.h></tt> that can be used to +conveniently cleanup a <tt/pam_response/ structure. (Note, this +include file is specific to the Linux-PAM sources, and whilst it will +work with Sun derived PAM implementations, it is not generally +distributed by Sun.) + +<sect2>Getting the name of a user<label id="pam-get-user"> + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_get_user(pam_handle_t *pamh, + const char **user, + const char *prompt); +</verb> +</tscreen> + +<p> +This is a <bf/Linux-PAM/ library function that returns the +(prospective) name of the user. To determine the username it does the +following things, in this order: +<itemize> + +<item> checks what <tt/pam_get_item(pamh, PAM_USER, ... );/ would have +returned. If this is not <tt/NULL/ this is what it returns. Otherwise, + +<item> obtains a username from the application via the <tt/pam_conv/ +mechanism, it prompts the user with the first non-<tt/NULL/ string in +the following list: +<itemize> + +<item> The <tt/prompt/ argument passed to the function +<item> What is returned by <tt/pam_get_item(pamh,PAM_USER_PROMPT, ... );/ +<item> The default prompt: ``Please enter username: '' + +</itemize> +</itemize> + +<p> +By whatever means the username is obtained, a pointer to it is +returned as the contents of <tt/*user/. Note, this memory should +<em/not/ be <tt/free()/'d by the module. Instead, it will be liberated +on the next call to <tt/pam_get_user()/, or by <tt/pam_end()/ when the +application ends its interaction with <bf/Linux-PAM/. + +<p> +Also, in addition, it should be noted that this function sets the +<tt/PAM_USER/ item that is associated with the <tt/pam_[gs]et_item()/ +function. + +<p> +The return value of this function is one of the following: +<itemize> + +<item> <tt/PAM_SUCCESS/ - username obtained. + +<item> <tt/PAM_CONV_AGAIN/ - converstation did not complete and the +caller is required to return control to the application, until such +time as the application has completed the conversation process. A +module calling <tt/pam_get_user()/ that obtains this return code, +should return <tt/PAM_INCOMPLETE/ and be prepared (when invoked the +next time) to recall <tt/pam_get_user()/ to fill in the user's name, +and then pick up where it left off as if nothing had happened. This +procedure is needed to support an event-driven application programming +model. + +<item> <tt/PAM_CONV_ERR/ - the conversation method supplied by the +application failed to obtain the username. + +</itemize> + +<sect2>Setting a Linux-PAM environment variable + +<p> +Synopsis: +<tscreen> +<verb> +extern int pam_putenv(pam_handle_t *pamh, const char *name_value); +</verb> +</tscreen> + +<p> +<bf/Linux-PAM/ comes equipped with a series of functions for +maintaining a set of <em/environment/ variables. The environment is +initialized by the call to <tt/pam_start()/ and is <bf/erased/ with a +call to <tt/pam_end()/. This <em/environment/ is associated with the +<tt/pam_handle_t/ pointer returned by the former call. + +<p> +The default environment is all but empty. It contains a single +<tt/NULL/ pointer, which is always required to terminate the +variable-list. The <tt/pam_putenv()/ function can be used to add a +new environment variable, replace an existing one, or delete an old +one. + +<p> +<itemize> +<item>Adding/replacing a variable<newline> + +To add or overwrite a <bf/Linux-PAM/ environment variable the value of +the argument <tt/name_value/, should be of the following form: +<tscreen> +<verb> +name_value="VARIABLE=VALUE OF VARIABLE" +</verb> +</tscreen> +Here, <tt/VARIABLE/ is the environment variable's name and what +follows the `<tt/=/' is its (new) value. (Note, that <tt/"VARIABLE="/ +is a valid value for <tt/name_value/, indicating that the variable is +set to <tt/""/.) + +<item> Deleting a variable<newline> + +To delete a <bf/Linux-PAM/ environment variable the value of +the argument <tt/name_value/, should be of the following form: +<tscreen> +<verb> +name_value="VARIABLE" +</verb> +</tscreen> +Here, <tt/VARIABLE/ is the environment variable's name and the absence +of an `<tt/=/' indicates that the variable should be removed. + +</itemize> + +<p> +In all cases <tt/PAM_SUCCESS/ indicates success. + +<sect2>Getting a Linux-PAM environment variable + +<p> +Synopsis: +<tscreen> +<verb> +extern const char *pam_getenv(pam_handle_t *pamh, const char *name); +</verb> +</tscreen> + +<p> +This function can be used to return the value of the given +variable. If the returned value is <tt/NULL/, the variable is not +known. + +<sect2>Listing the Linux-PAM environment + +<p> +Synopsis: +<tscreen> +<verb> +extern char * const *pam_getenvlist(pam_handle_t *pamh); +</verb> +</tscreen> + +<p> +This function returns a pointer to the entire <bf/Linux-PAM/ +environment array. At first sight the <em/type/ of the returned data +may appear a little confusing. It is basically a <em/read-only/ array +of character pointers, that lists the <tt/NULL/ terminated list of +environment variables set so far. + +<p> +Although, this is not a concern for the module programmer, we mention +here that an application should be careful to copy this entire array +before executing <tt/pam_end()/ otherwise all the variable information +will be lost. (There are functions in <tt/libpam_misc/ for this +purpose: <tt/pam_misc_copy_env()/ and <tt/pam_misc_drop_env()/.) + +<sect1>Other functions provided by <tt/libpam/ + +<sect2>Understanding errors + +<p> +<itemize> + +<item> +<tt>extern const char *pam_strerror(pam_handle_t *pamh, int errnum);</tt> + +<p> +This function returns some text describing the <bf/Linux-PAM/ error +associated with the argument <tt/errnum/. If the error is not +recognized <tt/``Unknown Linux-PAM error''/ is returned. + +</itemize> + +<sect2>Planning for delays + +<p> +<itemize> + +<item> +<tt>extern int pam_fail_delay(pam_handle_t *pamh, unsigned int +micro_sec)</tt> + +<p> +This function is offered by <bf/Linux-PAM/ to facilitate time delays +following a failed call to <tt/pam_authenticate()/ and before control +is returned to the application. When using this function the module +programmer should check if it is available with, +<tscreen> +<verb> +#ifdef PAM_FAIL_DELAY + .... +#endif /* PAM_FAIL_DELAY */ +</verb> +</tscreen> + +<p> +Generally, an application requests that a user is authenticated by +<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or +<tt/pam_chauthtok()/. These functions call each of the <em/stacked/ +authentication modules listed in the <bf/Linux-PAM/ configuration +file. As directed by this file, one of more of the modules may fail +causing the <tt/pam_...()/ call to return an error. It is desirable +for there to also be a pause before the application continues. The +principal reason for such a delay is security: a delay acts to +discourage <em/brute force/ dictionary attacks primarily, but also +helps hinder <em/timed/ (cf. covert channel) attacks. + +<p> +The <tt/pam_fail_delay()/ function provides the mechanism by which an +application or module can suggest a minimum delay (of <tt/micro_sec/ +<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time +requested with this function. Should <tt/pam_authenticate()/ fail, +the failing return to the application is delayed by an amount of time +randomly distributed (by up to 25%) about this longest value. + +<p> +Independent of success, the delay time is reset to its zero default +value when <bf/Linux-PAM/ returns control to the application. + +</itemize> + +<sect>What is expected of a module + +<p> +The module must supply a sub-set of the six functions listed +below. Together they define the function of a <bf/Linux-PAM +module/. Module developers are strongly urged to read the comments on +security that follow this list. + +<sect1> Overview + +<p> +The six module functions are grouped into four independent management +groups. These groups are as follows: <em/authentication/, +<em/account/, <em/session/ and <em/password/. To be properly defined, +a module must define all functions within at least one of these +groups. A single module may contain the necessary functions for +<em/all/ four groups. + +<sect2> Functional independence + +<p> +The independence of the four groups of service a module can offer +means that the module should allow for the possibility that any one of +these four services may legitimately be called in any order. Thus, the +module writer should consider the appropriateness of performing a +service without the prior success of some other part of the module. + +<p> +As an informative example, consider the possibility that an +application applies to change a user's authentication token, without +having first requested that <bf/Linux-PAM/ authenticate the user. In +some cases this may be deemed appropriate: when <tt/root/ wants to +change the authentication token of some lesser user. In other cases it +may not be appropriate: when <tt/joe/ maliciously wants to reset +<tt/alice/'s password; or when anyone other than the user themself +wishes to reset their <em/KERBEROS/ authentication token. A policy for +this action should be defined by any reasonable authentication scheme, +the module writer should consider this when implementing a given +module. + +<sect2> Minimizing administration problems + +<p> +To avoid system administration problems and the poor construction of a +<tt>/etc/pam.conf</tt> file, the module developer may define all +six of the following functions. For those functions that would not be +called, the module should return <tt/PAM_SERVICE_ERR/ and write an +appropriate message to the system log. When this action is deemed +inappropriate, the function would simply return <tt/PAM_IGNORE/. + +<sect2> Arguments supplied to the module + +<p> +The <tt/flags/ argument of each of the following functions can be +logically OR'd with <tt/PAM_SILENT/, which is used to inform the +module to not pass any <em/text/ (errors or warnings) to the +application. + +<p> +The <tt/argc/ and <tt/argv/ arguments are taken from the line +appropriate to this module---that is, with the <em/service_name/ +matching that of the application---in the configuration file (see the +<bf/Linux-PAM/ System Administrators' Guide). Together these two +parameters provide the number of arguments and an array of pointers to +the individual argument tokens. This will be familiar to C programmers +as the ubiquitous method of passing command arguments to the function +<tt/main()/. Note, however, that the first argument (<tt/argv[0]/) is +a true argument and <bf/not/ the name of the module. + +<sect1> Authentication management + +<p> +To be correctly initialized, <tt/PAM_SM_AUTH/ must be <tt/#define/'d +prior to including <tt><security/pam_modules.h></tt>. This will +ensure that the prototypes for static modules are properly declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, +int argc, const char **argv);</tt> + +<p> +This function performs the task of authenticating the user. + +<p> +The <tt/flags/ argument can be a logically OR'd with <tt/PAM_SILENT/ +and optionally take the following value: + +<p><descrip> +<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag> + return <tt/PAM_AUTH_ERR/ if the database of authentication +tokens for this authentication mechanism has a <tt/NULL/ entry for the +user. Without this flag, such a <tt/NULL/ token will lead to a success +without the user being prompted. +</descrip> + +<p> +Besides <tt/PAM_SUCCESS/ return values that can be sent by this +function are one of the following: + +<descrip> + +<tag><tt/PAM_AUTH_ERR/</tag> + The user was not authenticated +<tag><tt/PAM_CRED_INSUFFICIENT/</tag> + For some reason the application does not have sufficient +credentials to authenticate the user. +<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag> + The modules were not able to access the authentication +information. This might be due to a network or hardware failure etc. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The supplied username is not known to the authentication +service +<tag><tt/PAM_MAXTRIES/</tag> + One or more of the authentication modules has reached its +limit of tries authenticating the user. Do not try again. + +</descrip> + +<item> +<tt>PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function performs the task of altering the credentials of the +user with respect to the corresponding authorization +scheme. Generally, an authentication module may have access to more +information about a user than their authentication token. This +function is used to make such information available to the +application. It should only be called <em/after/ the user has been +authenticated but before a session has been established. + +<p> +Permitted flags, one of which, may be logically OR'd with +<tt/PAM_SILENT/ are, + +<p><descrip> +<tag><tt/PAM_ESTABLISH_CRED/</tag> + Set the credentials for the authentication service, +<tag><tt/PAM_DELETE_CRED/</tag> + Delete the credentials associated with the authentication service, +<tag><tt/PAM_REINITIALIZE_CRED/</tag> + Reinitialize the user credentials, and +<tag><tt/PAM_REFRESH_CRED/</tag> + Extend the lifetime of the user credentials. +</descrip> + +<p> +Prior to <bf/Linux-PAM-0.75/, and due to a deficiency with the way the +<tt/auth/ stack was handled in the case of the setcred stack being +processed, the module was required to attempt to return the same error +code as <tt/pam_sm_authenticate/ did. This was necessary to preserve +the logic followed by libpam as it executes the stack of +<em/authentication/ modules, when the application called either +<tt/pam_authenticate()/ or <tt/pam_setcred()/. Failing to do this, +led to confusion on the part of the System Administrator. + +<p> +For <bf/Linux-PAM-0.75/ and later, libpam handles the credential stack +much more sanely. The way the <tt/auth/ stack is navigated in order to +evaluate the <tt/pam_setcred()/ function call, independent of the +<tt/pam_sm_setcred()/ return codes, is exactly the same way that it +was navigated when evaluating the <tt/pam_authenticate()/ library +call. Typically, if a stack entry was ignored in evaluating +<tt/pam_authenticate()/, it will be ignored when libpam evaluates the +<tt/pam_setcred()/ function call. Otherwise, the return codes from +each module specific <tt/pam_sm_setcred()/ call are treated as +<tt/required/. + +<p> +Besides <tt/PAM_SUCCESS/, the module may return one of the following +errors: + +<p><descrip> +<tag><tt/PAM_CRED_UNAVAIL/</tag> + This module cannot retrieve the user's credentials. +<tag><tt/PAM_CRED_EXPIRED/</tag> + The user's credentials have expired. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to this authentication module. +<tag><tt/PAM_CRED_ERR/</tag> + This module was unable to set the credentials of the user. +</descrip> + +<p> +these, non-<tt/PAM_SUCCESS/, return values will typically lead to the +credential stack <em/failing/. The first such error will dominate in +the return value of <tt/pam_setcred()/. + +</itemize> + +<sect1> Account management + +<p> +To be correctly initialized, <tt/PAM_SM_ACCOUNT/ must be +<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. +This will ensure that the prototype for a static module is properly +declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function performs the task of establishing whether the user is +permitted to gain access at this time. It should be understood that +the user has previously been validated by an authentication +module. This function checks for other things. Such things might be: +the time of day or the date, the terminal line, remote +hostname, etc. . + +<p> +This function may also determine things like the expiration on +passwords, and respond that the user change it before continuing. + +<p> +Valid flags, which may be logically OR'd with <tt/PAM_SILENT/, are the +same as those applicable to the <tt/flags/ argument of +<tt/pam_sm_authenticate/. + +<p> +This function may return one of the following errors, + +<descrip> + +<tag><tt/PAM_ACCT_EXPIRED/</tag> + The user is no longer permitted access to the system. +<tag><tt/PAM_AUTH_ERR/</tag> + There was an authentication error. +<tag><tt/PAM_AUTHTOKEN_REQD/</tag> + The user's authentication token has expired. Before calling +this function again the application will arrange for a new one to be +given. This will likely result in a call to <tt/pam_sm_chauthtok()/. +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to the module's account management +component. + +</descrip> + +</itemize> + +<sect1> Session management + +<p> +To be correctly initialized, <tt/PAM_SM_SESSION/ must be +<tt/#define/'d prior to including +<tt><security/pam_modules.h></tt>. This will ensure that the +prototypes for static modules are properly declared. + +<p> +The following two functions are defined to handle the +initialization/termination of a session. For example, at the beginning +of a session the module may wish to log a message with the system +regarding the user. Similarly, at the end of the session the module +would inform the system that the user's session has ended. + +<p> +It should be possible for sessions to be opened by one application and +closed by another. This either requires that the module uses only +information obtained from <tt/pam_get_item()/, or that information +regarding the session is stored in some way by the operating system +(in a file for example). + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is called to commence a session. The only valid, but +optional, flag is <tt/PAM_SILENT/. + +<p> +As a return value, <tt/PAM_SUCCESS/ signals success and +<tt/PAM_SESSION_ERR/ failure. + +<item> +<tt>PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is called to terminate a session. The only valid, but +optional, flag is <tt/PAM_SILENT/. + +<p> +As a return value, <tt/PAM_SUCCESS/ signals success and +<tt/PAM_SESSION_ERR/ failure. + +</itemize> + +<sect1> Password management + +<p> +To be correctly initialized, <tt/PAM_SM_PASSWORD/ must be +<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. +This will ensure that the prototype for a static module is properly +declared. + +<p> +<itemize> + +<item> +<tt>PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int +argc, const char **argv);</tt> + +<p> +This function is used to (re-)set the authentication token of the +user. A valid flag, which may be logically OR'd with <tt/PAM_SILENT/, +can be built from the following list, + +<descrip> +<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag> + This argument indicates to the module that the users +authentication token (password) should only be changed if it has +expired. This flag is optional and <em/must/ be combined with one of +the following two flags. Note, however, the following two options are +<em/mutually exclusive/. + +<tag><tt/PAM_PRELIM_CHECK/</tag> + This indicates that the modules are being probed as to their +ready status for altering the user's authentication token. If the +module requires access to another system over some network it should +attempt to verify it can connect to this system on receiving this +flag. If a module cannot establish it is ready to update the user's +authentication token it should return <tt/PAM_TRY_AGAIN/, this +information will be passed back to the application. + +<tag><tt/PAM_UPDATE_AUTHTOK/</tag> + This informs the module that this is the call it should change +the authorization tokens. If the flag is logically OR'd with +<tt/PAM_CHANGE_EXPIRED_AUTHTOK/, the token is only changed if it has +actually expired. + +</descrip> + +<p> +Note, the <bf/Linux-PAM/ library calls this function twice in +succession. The first time with <tt/PAM_PRELIM_CHECK/ and then, if the +module does not return <tt/PAM_TRY_AGAIN/, subsequently with +<tt/PAM_UPDATE_AUTHTOK/. It is only on the second call that the +authorization token is (possibly) changed. + +<p> +<tt/PAM_SUCCESS/ is the only successful return value, valid +error-returns are: + +<descrip> +<tag><tt/PAM_AUTHTOK_ERR/</tag> + The module was unable to obtain the new authentication token. + +<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag> + The module was unable to obtain the old authentication token. + +<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag> + Cannot change the authentication token since it is currently +locked. + +<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag> + Authentication token aging has been disabled. + +<tag><tt/PAM_PERM_DENIED/</tag> + Permission denied. + +<tag><tt/PAM_TRY_AGAIN/</tag> + Preliminary check was unsuccessful. Signals an immediate return +to the application is desired. + +<tag><tt/PAM_USER_UNKNOWN/</tag> + The user is not known to the authentication token changing +service. + +</descrip> + +</itemize> + +<sect>Generic optional arguments + +<p> +Here we list the generic arguments that all modules can expect to +be passed. They are not mandatory, and their absence should be +accepted without comment by the module. + +<p> +<descrip> +<tag><tt/debug/</tag> + +Use the <tt/syslog(3)/ call to log debugging information to the system +log files. + +<tag><tt/no_warn/</tag> + +Instruct module to not give warning messages to the application. + +<tag><tt/use_first_pass/</tag> + +The module should not prompt the user for a password. Instead, it +should obtain the previously typed password (by a call to +<tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ item), and use that. If +that doesn't work, then the user will not be authenticated. (This +option is intended for <tt/auth/ and <tt/passwd/ modules only). + +<tag><tt/try_first_pass/</tag> + +The module should attempt authentication with the previously typed +password (by a call to <tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ +item). If that doesn't work, then the user is prompted for a +password. (This option is intended for <tt/auth/ modules only). + +<tag><tt/use_mapped_pass/</tag> + +<bf/WARNING:/ coding this functionality may cause the module writer to +break <em/local/ encryption laws. For example, in the U.S. there are +restrictions on the export computer code that is capable of strong +encryption. It has not been established whether this option is +affected by this law, but one might reasonably assume that it does +until told otherwise. For this reason, this option is not supported +by any of the modules distributed with <bf/Linux-PAM/. + +The intended function of this argument, however, is that the module +should take the existing authentication token from a previously +invoked module and use it as a key to retrieve the authentication +token for this module. For example, the module might create a strong +hash of the <tt/PAM_AUTHTOK/ item (established by a previously +executed module). Then, with logical-exclusive-or, use the result as a +<em/key/ to safely store/retrieve the authentication token for this +module in/from a local file <em/etc/. . + +<tag><tt/expose_account/</tag> + +<p> +In general the leakage of some information about user accounts is not +a secure policy for modules to adopt. Sometimes information such as +users names or home directories, or preferred shell, can be used to +attack a user's account. In some circumstances, however, this sort of +information is not deemed a threat: displaying a user's full name when +asking them for a password in a secured environment could also be +called being 'friendly'. The <tt/expose_account/ argument is a +standard module argument to encourage a module to be less discrete +about account information as it is deemed appropriate by the local +administrator. + +</descrip> + +<sect>Programming notes + +<p> +Here we collect some pointers for the module writer to bear in mind +when writing/developing a <bf/Linux-PAM/ compatible module. + +<sect1>Security issues for module creation + +<sect2>Sufficient resources + +<p> +Care should be taken to ensure that the proper execution of a module +is not compromised by a lack of system resources. If a module is +unable to open sufficient files to perform its task, it should fail +gracefully, or request additional resources. Specifically, the +quantities manipulated by the <tt/setrlimit(2)/ family of commands +should be taken into consideration. + +<sect2>Who's who? + +<p> +Generally, the module may wish to establish the identity of the user +requesting a service. This may not be the same as the username +returned by <tt/pam_get_user()/. Indeed, that is only going to be the +name of the user under whose identity the service will be given. This +is not necessarily the user that requests the service. + +<p> +In other words, user X runs a program that is setuid-Y, it grants the +user to have the permissions of Z. A specific example of this sort of +service request is the <em/su/ program: user <tt/joe/ executes +<em/su/ to become the user <em/jane/. In this situation X=<tt/joe/, +Y=<tt/root/ and Z=<tt/jane/. Clearly, it is important that the module +does not confuse these different users and grant an inappropriate +level of privilege. + +<p> +The following is the convention to be adhered to when juggling +user-identities. + +<p> +<itemize> +<item>X, the identity of the user invoking the service request. +This is the user identifier; returned by the function <tt/getuid(2)/. + +<item>Y, the privileged identity of the application used to grant the +requested service. This is the <em/effective/ user identifier; +returned by the function <tt/geteuid(2)/. + +<item>Z, the user under whose identity the service will be granted. +This is the username returned by <tt/pam_get_user(2)/ and also stored +in the <bf/Linux-PAM/ item, <tt/PAM_USER/. + +<item><bf/Linux-PAM/ has a place for an additional user identity that +a module may care to make use of. This is the <tt/PAM_RUSER/ item. +Generally, network sensitive modules/applications may wish to set/read +this item to establish the identity of the user requesting a service +from a remote location. + +</itemize> + +<p> +Note, if a module wishes to modify the identity of either the <tt/uid/ +or <tt/euid/ of the running process, it should take care to restore +the original values prior to returning control to the <bf/Linux-PAM/ +library. + +<sect2>Using the conversation function +<p> +Prior to calling the conversation function, the module should reset +the contents of the pointer that will return the applications +response. This is a good idea since the application may fail to fill +the pointer and the module should be in a position to notice! + +<p> +The module should be prepared for a failure from the conversation. The +generic error would be <tt/PAM_CONV_ERR/, but anything other than +<tt/PAM_SUCCESS/ should be treated as indicating failure. + +<sect2>Authentication tokens + +<p> +To ensure that the authentication tokens are not left lying around the +items, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/, are not available to +the application: they are defined in +<tt><security/pam_modules.h></tt>. This is ostensibly for +security reasons, but a maliciously programmed application will always +have access to all memory of the process, so it is only superficially +enforced. As a general rule the module should overwrite +authentication tokens as soon as they are no longer needed. +Especially before <tt/free()/'ing them. The <bf/Linux-PAM/ library is +required to do this when either of these authentication token items +are (re)set. + +<p> +Not to dwell too little on this concern; should the module store the +authentication tokens either as (automatic) function variables or +using <tt/pam_[gs]et_data()/ the associated memory should be +over-written explicitly before it is released. In the case of the +latter storage mechanism, the associated <tt/cleanup()/ function +should explicitly overwrite the <tt/*data/ before <tt/free()/'ing it: +for example, + +<tscreen> +<verb> +/* + * An example cleanup() function for releasing memory that was used to + * store a password. + */ + +int cleanup(pam_handle_t *pamh, void *data, int error_status) +{ + char *xx; + + if ((xx = data)) { + while (*xx) + *xx++ = '\0'; + free(data); + } + return PAM_SUCCESS; +} +</verb> +</tscreen> + +<sect1>Use of <tt/syslog(3)/ + +<p> +Only rarely should error information be directed to the user. Usually, +this is to be limited to ``<em/sorry you cannot login now/'' type +messages. Information concerning errors in the configuration file, +<tt>/etc/pam.conf</tt>, or due to some system failure encountered by +the module, should be written to <tt/syslog(3)/ with +<em/facility-type/ <tt/LOG_AUTHPRIV/. + +<p> +With a few exceptions, the level of logging is, at the discretion of +the module developer. Here is the recommended usage of different +logging levels: + +<p> +<itemize> + +<item> +As a general rule, errors encountered by a module should be logged at +the <tt/LOG_ERR/ level. However, information regarding an unrecognized +argument, passed to a module from an entry in the +<tt>/etc/pam.conf</tt> file, is <bf/required/ to be logged at the +<tt/LOG_ERR/ level. + +<item> +Debugging information, as activated by the <tt/debug/ argument to the +module in <tt>/etc/pam.conf</tt>, should be logged at the +<tt/LOG_DEBUG/ level. + +<item> +If a module discovers that its personal configuration file or some +system file it uses for information is corrupted or somehow unusable, +it should indicate this by logging messages at level, <tt/LOG_ALERT/. + +<item> +Shortages of system resources, such as a failure to manipulate a file +or <tt/malloc()/ failures should be logged at level <tt/LOG_CRIT/. + +<item> +Authentication failures, associated with an incorrectly typed password +should be logged at level, <tt/LOG_NOTICE/. + +</itemize> + +<sect1> Modules that require system libraries + +<p> +Writing a module is much like writing an application. You have to +provide the "conventional hooks" for it to work correctly, like +<tt>pam_sm_authenticate()</tt> etc., which would correspond to the +<tt/main()/ function in a normal function. + +<p> +Typically, the author may want to link against some standard system +libraries. As when one compiles a normal program, this can be done for +modules too: you simply append the <tt>-l</tt><em>XXX</em> arguments +for the desired libraries when you create the shared module object. To +make sure a module is linked to the <tt>lib<em>whatever</em>.so</tt> +library when it is <tt>dlopen()</tt>ed, try: +<tscreen> +<verb> +% gcc -shared -Xlinker -x -o pam_module.so pam_module.o -lwhatever +</verb> +</tscreen> + +<sect1> Added requirements for <em/statically/ loaded modules. + +<!-- + Copyright (C) Michael K. Johnson 1996. + Last modified: AGM 1996/5/31. + --> + +<p> +Modules may be statically linked into libpam. This should be true of +all the modules distributed with the basic <bf/Linux-PAM/ +distribution. To be statically linked, a module needs to export +information about the functions it contains in a manner that does not +clash with other modules. + +The extra code necessary to build a static module should be delimited +with <tt/#ifdef PAM_STATIC/ and <tt/#endif/. The static code should do +the following: +<itemize> +<item> Define a single structure, <tt/struct pam_module/, called +<tt>_pam_<it>modname</it>_modstruct</tt>, where +<tt><it>modname</it></tt> is the name of the module <bf/as used in the +filesystem/ but without the leading directory name (generally +<tt>/usr/lib/security/</tt> or the suffix (generally <tt/.so/). + +</itemize> + +<p> +As a simple example, consider the following module code which defines +a module that can be compiled to be <em/static/ or <em/dynamic/: + +<p> +<tscreen> +<verb> +#include <stdio.h> /* for NULL define */ + +#define PAM_SM_PASSWORD /* the only pam_sm_... function declared */ +#include <security/pam_modules.h> + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC /* for the case that this module is static */ + +struct pam_module _pam_modname_modstruct = { /* static module data */ + "pam_modname", + NULL, + NULL, + NULL, + NULL, + NULL, + pam_sm_chauthtok, +}; + +#endif /* end PAM_STATIC */ +</verb> +</tscreen> + +<p> +To be linked with <em/libpam/, staticly-linked modules must be built +from within the <tt>Linux-PAM-X.YY/modules/</tt> subdirectory of the +<bf/Linux-PAM/ source directory as part of a normal build of the +<bf/Linux-PAM/ system. + +The <em/Makefile/, for the module in question, must execute the +<tt/register_static/ shell script that is located in the +<tt>Linux-PAM-X.YY/modules/</tt> subdirectory. This is to ensure that +the module is properly registered with <em/libpam/. + +The <bf/two/ manditory arguments to <tt/register_static/ are the +title, and the pathname of the object file containing the module's +code. The pathname is specified relative to the +<tt>Linux-PAM-X.YY/modules</tt> directory. The pathname may be an +empty string---this is for the case that a single object file needs to +register more than one <tt/struct pam_module/. In such a case, exactly +one call to <tt/register_static/ must indicate the object file. + +<p> +Here is an example; a line in the <em/Makefile/ might look like this: +<tscreen> +<verb> +register: +ifdef STATIC + (cd ..; ./register_static pam_modname pam_modname/pam_modname.o) +endif +</verb> +</tscreen> + +For some further examples, see the <tt>modules</tt> subdirectory of +the current <bf/Linux-PAM/ distribution. + +<sect>An example module file + +<p> +At some point, we may include a fully commented example of a module in +this document. For now, we point the reader to these two locations in +the public CVS repository: +<itemize> +<item> A module that always succeeds: <tt><htmlurl +url="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_permit/" +name="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_permit/" +></tt> +<item> A module that always fails: <tt><htmlurl +url="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_deny/" +name="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_deny/" +></tt> +</itemize> + +<sect>Files + +<p><descrip> + +<tag><tt>/usr/lib/libpam.so.*</tt></tag> + +the shared library providing applications with access to +<bf/Linux-PAM/. + +<tag><tt>/etc/pam.conf</tt></tag> + +the <bf/Linux-PAM/ configuration file. + +<tag><tt>/usr/lib/security/pam_*.so</tt></tag> + +the primary location for <bf/Linux-PAM/ dynamically loadable object +files; the modules. + +</descrip> + +<sect>See also + +<p><itemize> +<item>The <bf/Linux-PAM/ System Administrators' Guide. +<item>The <bf/Linux-PAM/ Application Writers' Guide. +<item> +V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE +AUTHENTICATION MODULES'', Open Software Foundation Request For +Comments 86.0, October 1995. +</itemize> + +<sect>Notes + +<p> +I intend to put development comments here... like ``at the moment +this isn't actually supported''. At release time what ever is in +this section will be placed in the Bugs section below! :) + +<p> +<itemize> +<item> +Perhaps we should keep a registry of data-names as used by +<tt/pam_[gs]et_data()/ so there are no unintentional problems due to +conflicts? + +<item> +<tt/pam_strerror()/ should be internationalized.... + +<item> +There has been some debate about whether <tt/initgroups()/ should be +in an application or in a module. It was settled by Sun who stated +that initgroups is an action of the <em/application/. The modules are +permitted to add additional groups, however. + +<item> +Refinements/futher suggestions to <tt/syslog(3)/ usage by modules are +needed. + +</itemize> + +<sect>Author/acknowledgments + +<p> +This document was written by Andrew G. Morgan +(<tt/morgan@kernel.org/) with many contributions from +<!-- insert credits here --> +<!-- + an sgml list of people to credit for their contributions to Linux-PAM + $Id: pam_modules.sgml,v 1.1.1.2 2002/09/15 20:08:25 hartmans Exp $ + --> +Chris Adams, +Peter Allgeyer, +Tim Baverstock, +Tim Berger, +Craig S. Bell, +Derrick J. Brashear, +Ben Buxton, +Seth Chaiklin, +Oliver Crow, +Chris Dent, +Marc Ewing, +Cristian Gafton, +Emmanuel Galanos, +Brad M. Garcia, +Eric Hester, +Roger Hu, +Eric Jacksch, +Michael K. Johnson, +David Kinchlea, +Olaf Kirch, +Marcin Korzonek, +Stephen Langasek, +Nicolai Langfeldt, +Elliot Lee, +Luke Kenneth Casson Leighton, +Al Longyear, +Ingo Luetkebohle, +Marek Michalkiewicz, +Robert Milkowski, +Aleph One, +Martin Pool, +Sean Reifschneider, +Jan Rekorajski, +Erik Troan, +Theodore Ts'o, +Jeff Uphoff, +Myles Uyema, +Savochkin Andrey Vladimirovich, +Ronald Wahl, +David Wood, +John Wilmes, +Joseph S. D. Yao +and +Alex O. Yuriev. + +<p> +Thanks are also due to Sun Microsystems, especially to Vipin Samar and +Charlie Lai for their advice. At an early stage in the development of +<bf/Linux-PAM/, Sun graciously made the documentation for their +implementation of PAM available. This act greatly accelerated the +development of <bf/Linux-PAM/. + +<sect>Bugs/omissions + +<p> +Few PAM modules currently exist. Few PAM-aware applications exist. +This document is hopelessly unfinished. Only a partial list of people is +credited for all the good work they have done. + +<sect>Copyright information for this document + +<p> +Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. +<newline> +Email: <tt><morgan@kernel.org></tt> + +<p> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +<p> +<itemize> + +<item> +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +<item> +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +<item> +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +</itemize> + +<p> +<bf/Alternatively/, this product may be distributed under the terms of +the GNU General Public License (GPL), in which case the provisions of +the GNU GPL are required <bf/instead of/ the above restrictions. +(This clause is necessary due to a potential bad interaction between +the GNU GPL and the restrictions contained in a BSD-style copyright.) + +<p> +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +<p> +<tt>$Id: pam_modules.sgml,v 1.1.1.2 2002/09/15 20:08:25 hartmans Exp $</tt> + +</article> diff --git a/Linux-PAM/doc/pam_source.sgml b/Linux-PAM/doc/pam_source.sgml new file mode 100644 index 00000000..0b7fcb8f --- /dev/null +++ b/Linux-PAM/doc/pam_source.sgml @@ -0,0 +1,1160 @@ +<!doctype linuxdoc system> + +<!-- + + $Id: pam_source.sgml,v 1.1.1.2 2002/09/15 20:08:25 hartmans Exp $ + + Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. + +Redistribution and use in source (sgml) and binary (derived) forms, +with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License, in which case the provisions of the GNU +GPL are required INSTEAD OF the above restrictions. (This clause is +necessary due to a potential bad interaction between the GNU GPL and +the restrictions contained in a BSD-style copyright.) + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + + --> + +<article> + +<title>The Linux-PAM System Administrators' Guide +<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> +<date>DRAFT v0.76 2002/06/26 +<abstract> +This manual documents what a system-administrator needs to know about +the <bf>Linux-PAM</bf> library. It covers the correct syntax of the +PAM configuration file and discusses strategies for maintaining a +secure system. +</abstract> + +<!-- Table of contents --> +<toc> + +<!-- Begin the document --> + +<sect>Introduction + +<p><bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a +suite of shared libraries that enable the local system administrator +to choose how applications authenticate users. + +<p>In other words, without (rewriting and) recompiling a PAM-aware +application, it is possible to switch between the authentication +mechanism(s) it uses. Indeed, one may entirely upgrade the local +authentication system without touching the applications themselves. + +<p>Historically an application that has required a given user to be +authenticated, has had to be compiled to use a specific authentication +mechanism. For example, in the case of traditional UN*X systems, the +identity of the user is verified by the user entering a correct +password. This password, after being prefixed by a two character +``salt'', is encrypted (with crypt(3)). The user is then authenticated +if this encrypted password is identical to the second field of the +user's entry in the system password database (the <tt>/etc/passwd</tt> +file). On such systems, most if not all forms of privileges are +granted based on this single authentication scheme. Privilege comes in +the form of a personal user-identifier (<tt/uid/) and membership of +various groups. Services and applications are available based on the +personal and group identity of the user. Traditionally, group +membership has been assigned based on entries in the +<tt>/etc/group</tt> file. + +<p> +Unfortunately, increases in the speed of computers and the +widespread introduction of network based computing, have made once +secure authentication mechanisms, such as this, vulnerable to +attack. In the light of such realities, new methods of authentication +are continuously being developed. + +<p> +It is the purpose of the <bf/Linux-PAM/ project to separate the +development of privilege granting software from the development of +secure and appropriate authentication schemes. This is accomplished +by providing a library of functions that an application may use to +request that a user be authenticated. This PAM library is configured +locally with a system file, <tt>/etc/pam.conf</tt> (or a series of +configuration files located in <tt>/etc/pam.d/</tt>) to authenticate a +user request via the locally available authentication modules. The +modules themselves will usually be located in the directory +<tt>/lib/security</tt> and take the form of dynamically loadable +object files (see <tt/dlopen(3)/). + +<sect>Some comments on the text<label id="text-conventions"> + +<p> +Before proceeding to read the rest of this document, it should be +noted that the text assumes that certain files are placed in certain +directories. Where they have been specified, the conventions we adopt +here for locating these files are those of the relevant RFC (RFC-86.0, +see <ref id="see-also-sec" name="bibliography">). If you are using a +distribution of Linux (or some other operating system) that supports +PAM but chooses to distribute these files in a diferent way you should +be careful when copying examples directly from the text. + +<p> +As an example of the above, where it is explicit, the text assumes +that PAM loadable object files (the <em/modules/) are to be located in +the following directory: <tt>/lib/security/</tt>. This is generally +the location that seems to be compatible with the Linux File System +Standard (the FSSTND). On Solaris, which has its own licensed version +of PAM, and some other implementations of UN*X, these files can be +found in <tt>/usr/lib/security</tt>. Please be careful to perform the +necessary transcription when using the examples from the text. + +<sect>Overview<label id="overview-section"> + +<p> +For the uninitiated, we begin by considering an example. We take an +application that grants some service to users; <em/login/ is one such +program. <em/Login/ does two things, it first establishes that the +requesting user is whom they claim to be and second provides them with +the requested service: in the case of <em/login/ the service is a +command shell (<em>bash, tcsh, zsh, etc.</em>) running with the +identity of the user. + +<p> +Traditionally, the former step is achieved by the <em/login/ +application prompting the user for a password and then verifying that +it agrees with that located on the system; hence verifying that +as far as the system is concerned the user is who they claim to be. +This is the task that is delegated to <bf/Linux-PAM/. + +<p> +From the perspective of the application programmer (in this case the +person that wrote the <em/login/ application), <bf/Linux-PAM/ takes +care of this authentication task -- verifying the identity of the user. + +<p> +The flexibility of <bf/Linux-PAM/ is that <em/you/, the system +administrator, have the freedom to stipulate which authentication +scheme is to be used. You have the freedom to set the scheme for +any/all PAM-aware applications on your Linux system. That is, you can +authenticate from anything as naive as <em/simple trust/ +(<tt/pam_permit/) to something as paranoid as a combination of a +retinal scan, a voice print and a one-time password! + +<p> +To illustrate the flexibility you face, consider the following +situation: a system administrator (parent) wishes to improve the +mathematical ability of her users (children). She can configure their +favorite ``Shoot 'em up game'' (PAM-aware of course) to authenticate +them with a request for the product of a couple of random numbers less +than 12. It is clear that if the game is any good they will soon learn +their <em/multiplication tables/. As they mature, the authentication +can be upgraded to include (long) division! + +<p> +<bf/Linux-PAM/ deals with four separate types of (management) +task. These are: <em/authentication management/; <em/account +management/; <em/session management/; and <em/password management/. +The association of the preferred management scheme with the behavior +of an application is made with entries in the relevant <bf/Linux-PAM/ +configuration file. The management functions are performed by +<em/modules/ specified in the configuration file. The syntax for this +file is discussed in the section <ref id="configuration" +name="below">. + +<p> +Here is a figure that describes the overall organization of +<bf/Linux-PAM/. +<tscreen> +<verb> + +----------------+ + | application: X | + +----------------+ / +----------+ +================+ + | authentication-[---->--\--] Linux- |--<--| PAM config file| + | + [----<--/--] PAM | |================| + |[conversation()][--+ \ | | | X auth .. a.so | + +----------------+ | / +-n--n-----+ | X auth .. b.so | + | | | __| | | _____/ + | service user | A | | |____,-----' + | | | V A + +----------------+ +------|-----|---------+ -----+------+ + +---u-----u----+ | | | + | auth.... |--[ a ]--[ b ]--[ c ] + +--------------+ + | acct.... |--[ b ]--[ d ] + +--------------+ + | password |--[ b ]--[ c ] + +--------------+ + | session |--[ e ]--[ c ] + +--------------+ +</verb> +</tscreen> +By way of explanation, the left of the figure represents the +application; application X. Such an application interfaces with the +<bf/Linux-PAM/ library and knows none of the specifics of its +configured authentication method. The <bf/Linux-PAM/ library (in the +center) consults the contents of the PAM configuration file and loads +the modules that are appropriate for application-X. These modules fall +into one of four management groups (lower-center) and are stacked in +the order they appear in the configuration file. These modules, when +called by <bf/Linux-PAM/, perform the various authentication tasks for +the application. Textual information, required from/or offered to the +user, can be exchanged through the use of the application-supplied +<em/conversation/ function. + +<sect1>Getting started + +<p> +The following text was contributed by Seth Chaiklin: +<tscreen> +<verb> +To this point, we have described how PAM should work in an +ideal world, in which all applications are coded properly. +However, at the present time (October 1998), this is far +from the case. Therefore, here are some practical considerations +in trying to use PAM in your system. + +Why bother, is it really worth all the trouble? + +If you running Linux as a single user system, or in an +environment where all the users are trusted, then there +is no real advantage for using PAM. +</verb> +</tscreen> + +<p> +<BF>Ed:</BF> there is actually an advantage since you can <em/dummy +down/ the authentication to the point where you don't have +any... Almost like Win95. +<p> +In a networked environment, it is clear that you need to think a +little more about how users etc., are authenticated:] + +<p> +<tscreen> +<verb> +If you are running Linux as a server, where several different +services are being provided (e.g., WWW with areas restricted by +password control, PPP), then there can be some real and interesting +value for PAM. In particular, through the use of modules, PAM can +enable a program to search through several different password +databases, even if that program is not explicitly coded for +that particular database. Here are some examples of the possibilities +that this enables. + + o Apache has a module that provides PAM services. Now + authentication + to use particular directories can be conducted by PAM, which + means that the range of modules that are available to PAM can + be used, including RADIUS, NIS, NCP (which means that Novell + password databases can be used). + + o pppd has a PAMified version (available from RedHat) Now it is + possible to use a series of databases to authenticate ppp users. + In addition to the normal Linux-based password databases (such + as /etc/passwd and /etc/shadow), you can use PAM modules to + authenticate against Novell password databases or NT-based + password databases. + + o The preceding two examples can be combined. Imagaine that the + persons in your office/department are already registered with a + username and password in a Novell or NT LAN. If you wanted to + use this database on your Linux server (for PPP access, for + web access, or even for normal shell access), you can use PAM + to authenticate against this existing database, rather than + maintain a separate database on both Linux and the LAN server. + + +Can I use PAM for any program that requires authentication? + +Yes and no. Yes, if you have access to the source code, and can +add the appropriate PAM functions. No, if you do not have access +to the source code, and the binary does not have the PAM functions +included. + +In other words, if a program is going to use PAM, then it has to +have PAM functions explicitly coded into the program. If they +are not, then it is not possible to use PAM. + +How can I tell whether a program has PAM coded into it or not? + +A quick-and-dirty (but not always reliable) method is to ldd +<programname> +If libpam and libpam_misc are not among the libraries that the program +uses, then it is not going to work with PAM. However, it is possible +that the libraries are included, but there are still problems, because +the PAM coding in the program does not work as it should. So a +more reliable method is to make the follow tests. + +In the /etc/pam.d directory, one needs to make a configuration file +for the program that one wants to run. The exact name of the +configuration +file is hard-coded into the program. Usually, it is the same name as +the +program, but not always. For sake of illustration, let's assume that +the program is named "pamprog" and the name of the configuration file +is /etc/pam.d/pamprog. + +In the /etc/pam.d/pamprog but the following two lines: + +auth required pam_permit.so +auth required pam_warn.so + + +Now try to use pamprog. The first line in the configuration file +says that all users are permitted. The second line will write a +warning to your syslog file (or whether you syslog is writing + +messages). If this test succeeds, then you know that you have +a program that can understand pam, and you can start the more +interesting work of deciding how to stack modules in your +/etc/pam.d/pamprog file. +</verb> +</tscreen> + +<sect>The Linux-PAM configuration file +<label id="configuration"> + +<p> +<bf/Linux-PAM/ is designed to provide the system administrator with a +great deal of flexibility in configuring the privilege granting +applications of their system. The local configuration of those aspects +of system security controlled by <tt/Linux-PAM/ is contained in one of +two places: either the single system file, <tt>/etc/pam.conf</tt>; or +the <tt>/etc/pam.d/</tt> directory. In this section we discuss the +correct syntax of and generic options respected by entries to these +files. + +<sect1>Configuration file syntax + +<p> +The reader should note that the <bf/Linux-PAM/ specific tokens in this +file are case <em/insensitive/. The module paths, however, are case +sensitive since they indicate a file's <em/name/ and reflect the case +dependence of typical Linux file-systems. The case-sensitivity of the +arguments to any given module is defined for each module in turn. + +<p> +In addition to the lines described below, there are two <em/special/ +characters provided for the convenience of the system administrator: +comments are preceded by a `<tt/#/' and extend to the +next end-of-line; also, module specification lines may be extended +with a `<tt/\/' escaped newline. + +<p> +A general configuration line of the <tt>/etc/pam.conf</tt> file has +the following form: +<tscreen> +<verb> +service-name module-type control-flag module-path args +</verb> +</tscreen> +Below, we explain the meaning of each of these tokens. The second (and +more recently adopted) way of configuring <bf/Linux-PAM/ is via the +contents of the <tt>/etc/pam.d/</tt> directory. Once we have explained +the meaning of the above tokens, we will describe this method. + +<p> +<descrip> +<tag><tt/service-name/</tag> +The name of the service associated with this entry. Frequently the +service name is the conventional name of the given application. For +example, `<tt/ftpd/', `<tt/rlogind/' and `<tt/su/', <em/etc./ . + +<p> +There is a special <tt/service-name/, reserved for defining a default +authentication mechanism. It has the name `<tt/OTHER/' and may be +specified in either lower or upper case characters. Note, when there +is a module specified for a named service, the `<tt/OTHER/' entries +are ignored. + +<tag><tt/module-type/</tag> +One of (currently) four types of module. The four types are as +follows: +<itemize> +<item> <tt/auth/; this module type provides two aspects of +authenticating the user. Firstly, it establishes that the user is who +they claim to be, by instructing the application to prompt the user +for a password or other means of identification. Secondly, the module +can grant <tt/group/ membership (independently of the +<tt>/etc/groups</tt> file discussed above) or other privileges through +its <em/credential/ granting properties. + +<item> <tt/account/; this module performs non-authentication based +account management. It is typically used to restrict/permit access to +a service based on the time of day, currently available system +resources (maximum number of users) or perhaps the location of the +applicant user---`<tt/root/' login only on the console. + +<item> <tt/session/; primarily, this module is associated with doing +things that need to be done for the user before/after they can be +given service. Such things include the logging of information +concerning the opening/closing of some data exchange with a user, +mounting directories, etc. . + +<item> <tt/password/; this last module type is required for updating the +authentication token associated with the user. Typically, there is one +module for each `challenge/response' based authentication (<tt/auth/) +module-type. + +</itemize> + +<tag><tt/control-flag/</tag> + +The control-flag is used to indicate how the PAM library will react to +the success or failure of the module it is associated with. Since +modules can be <em/stacked/ (modules of the same type execute in +series, one after another), the control-flags determine the relative +importance of each module. The application is not made aware of the +individual success or failure of modules listed in the +`<tt>/etc/pam.conf</tt>' file. Instead, it receives a summary +<em/success/ or <em/fail/ response from the <bf/Linux-PAM/ library. +The order of execution of these modules is that of the entries in the +<tt>/etc/pam.conf</tt> file; earlier entries are executed before later +ones. As of Linux-PAM v0.60, this <em/control-flag/ can be defined +with one of two syntaxes. + +<p> +The simpler (and historical) syntax for the control-flag is a single +keyword defined to indicate the severity of concern associated with +the success or failure of a specific module. There are four such +keywords: <tt/required/, <tt/requisite/, <tt/sufficient/ and +<tt/optional/. + +<p> +The Linux-PAM library interprets these keywords in the following +manner: + +<itemize> + +<item> <tt/required/; this indicates that the success of the module is +required for the <tt/module-type/ facility to succeed. Failure of this +module will not be apparent to the user until all of the remaining +modules (of the same <tt/module-type/) have been executed. + +<item> <tt/requisite/; like <tt/required/, however, in the case that +such a module returns a failure, control is directly returned to the +application. The return value is that associated with the <em/first/ +<tt/required/ or <tt/requisite/ module to fail. Note, this flag can be +used to protect against the possibility of a user getting the +opportunity to enter a password over an unsafe medium. It is +conceivable that such behavior might inform an attacker of valid +accounts on a system. This possibility should be weighed against the +not insignificant concerns of exposing a sensitive password in a +hostile environment. + +<item> <tt/sufficient/; the success of this module is deemed +`<em/sufficient/' to satisfy the <bf/Linux-PAM/ library that this +module-type has succeeded in its purpose. In the event that no +previous <tt/required/ module has failed, no more `<em/stacked/' +modules of this type are invoked. (Note, in this case subsequent +<tt/required/ modules are <bf/not/ invoked.). A failure of this module +is not deemed as fatal to satisfying the application that this +<tt/module-type/ has succeeded. + +<item> <tt/optional/; as its name suggests, this <tt/control-flag/ +marks the module as not being critical to the success or failure of +the user's application for service. In general, <bf/Linux-PAM/ +ignores such a module when determining if the module stack will +succeed or fail. However, in the absence of any definite successes or +failures of previous or subsequent stacked modules this module will +determine the nature of the response to the application. One example +of this latter case, is when the other modules return something like +<tt/PAM_IGNORE/. + +</itemize> + +<p> +The more elaborate (newer) syntax is much more specific and gives the +administrator a great deal of control over how the user is +authenticated. This form of the control flag is delimeted with square +brackets and consists of a series of <tt/value=action/ tokens: +<tscreen> +<verb> + [value1=action1 value2=action2 ...] +</verb> +</tscreen> + +<p> +Here, <tt/valueI/ is one of the following <em/return values/: +<tt/success/; <tt/open_err/; <tt/symbol_err/; <tt/service_err/; +<tt/system_err/; <tt/buf_err/; <tt/perm_denied/; <tt/auth_err/; +<tt/cred_insufficient/; <tt/authinfo_unavail/; <tt/user_unknown/; +<tt/maxtries/; <tt/new_authtok_reqd/; <tt/acct_expired/; +<tt/session_err/; <tt/cred_unavail/; <tt/cred_expired/; <tt/cred_err/; +<tt/no_module_data/; <tt/conv_err/; <tt/authtok_err/; +<tt/authtok_recover_err/; <tt/authtok_lock_busy/; +<tt/authtok_disable_aging/; <tt/try_again/; <tt/ignore/; <tt/abort/; +<tt/authtok_expired/; <tt/module_unknown/; <tt/bad_item/; and +<tt/default/. The last of these (<tt/default/) can be used to set the +action for those return values that are not explicitly defined. + +<p> +The <tt/actionI/ can be a positive integer or one of the following +tokens: <tt/ignore/; <tt/ok/; <tt/done/; <tt/bad/; <tt/die/; and +<tt/reset/. A positive integer, <tt/J/, when specified as the action, +can be used to indicate that the next <em/J/ modules of the current +module-type will be skipped. In this way, the administrator can +develop a moderately sophisticated stack of modules with a number of +different paths of execution. Which path is taken can be determined +by the reactions of individual modules. + +<p> +<itemize> +<item><tt/ignore/ - when used with a stack of modules, the module's + return status will not contribute to the return code the application + obtains. +<item><tt/bad/ - this action indicates that the return code should be + thought of as indicative of the module failing. If this module is + the first in the stack to fail, its status value will be used for + that of the whole stack. +<item><tt/die/ - equivalent to <tt/bad/ with the side effect of + terminating the module stack and PAM immediately returning to the + application. +<item><tt/ok/ - this tells <bf/PAM/ that the administrator thinks this + return code should contribute directly to the return code of the full + stack of modules. In other words, if the former state of the stack + would lead to a return of <tt/PAM_SUCCESS/, the module's return code + will override this value. Note, if the former state of the stack + holds some value that is indicative of a modules failure, this 'ok' + value will not be used to override that value. +<item><tt/done/ - equivalent to <tt/ok/ with the side effect of + terminating the module stack and PAM immediately returning to the + application. +<item><tt/reset/ - clear all memory of the state of the module stack and + start again with the next stacked module. +</itemize> + +<p> +Each of the four keywords: <tt/required/; <tt/requisite/; +<tt/sufficient/; and <tt/optional/, have an equivalent expression in +terms of the <tt/[...]/ syntax. They are as follows: +<itemize> +<item><tt/required/ is equivalent to +<tt/[success=ok new_authtok_reqd=ok ignore=ignore default=bad]/ +<item><tt/requisite/ is equivalent to +<tt/[success=ok new_authtok_reqd=ok ignore=ignore default=die]/ +<item><tt/sufficient/ is equivalent to +<tt/[success=done new_authtok_reqd=done default=ignore]/ +<item><tt/optional/ is equivalent to +<tt/[success=ok new_authtok_reqd=ok default=ignore]/ +</itemize> + +<p> +Just to get a feel for the power of this new syntax, here is a taste +of what you can do with it. With <bf/Linux-PAM-0.63/, the notion of +client plug-in agents was introduced. This is something that makes it +possible for PAM to support machine-machine authentication using the +transport protocol inherent to the client/server application. With +the ``<tt/[ ... value=action ... ]/'' control syntax, it is possible +for an application to be configured to support binary prompts with +compliant clients, but to gracefully fall over into an alternative +authentication mode for older, legacy, applications. + +<tag> <tt/module-path/</tag> + +The path-name of the dynamically loadable object file; <em/the +pluggable module/ itself. If the first character of the module path is +`<tt>/</tt>', it is assumed to be a complete path. If this is not the +case, the given module path is appended to the default module path: +<tt>/lib/security</tt> (but see the notes <ref id="text-conventions" +name="above">). + +<tag> <tt/args/</tag> + +The <tt/args/ are a list of tokens that are passed to the module when +it is invoked. Much like arguments to a typical Linux shell command. +Generally, valid arguments are optional and are specific to any given +module. Invalid arguments are ignored by a module, however, when +encountering an invalid argument, the module is required to write an +error to <tt/syslog(3)/. For a list of <em/generic/ options see the +next section. + +Note, if you wish to include spaces in an argument, you should +surround that argument with square brackets. For example: +<tscreen> +<verb> +squid auth required pam_mysql.so user=passwd_query passwd=mada \ + db=eminence [query=select user_name from internet_service where \ + user_name='%u' and password=PASSWORD('%p') and \ + service='web_proxy'] +</verb> +</tscreen> +Note, when using this convention, you can include `<tt/[/' characters +inside the string, and if you wish to include a `<tt/]/' character +inside the string that will survive the argument parsing, you should +use `<tt/\[/'. In other words: +<tscreen> +<verb> +[..[..\]..] --> ..[..].. +</verb> +</tscreen> + +</descrip> + +<p> +Any line in (one of) the configuration file(s), that is not formatted +correctly, will generally tend (erring on the side of caution) to make +the authentication process fail. A corresponding error is written to +the system log files with a call to <tt/syslog(3)/. + +<sect1>Directory based configuration + +<p> +More flexible than the single configuration file, as of version 0.56, +it is possible to configure <tt>libpam</tt> via the contents of the +<tt>/etc/pam.d/</tt> directory. In this case the directory is filled +with files each of which has a filename equal to a service-name (in +lower-case): it is the personal configuration file for the named +service. + +<p> +<bf/Linux-PAM/ can be compiled in one of two modes. The preferred +mode uses either <tt>/etc/pam.d/</tt> or <tt>/etc/pam.conf</tt> +configuration but not both. That is to say, if there is a +<tt>/etc/pam.d/</tt> directory then libpam only uses the files +contained in this directory. However, in the absence of the +<tt>/etc/pam.d/</tt> directory the <tt>/etc/pam.conf</tt> file is used +(this is likely to be the mode your preferred distribution uses). The +other mode is to use both <tt>/etc/pam.d/</tt> and +<tt>/etc/pam.conf</tt> in sequence. In this mode, entries in +<tt>/etc/pam.d/</tt> override those of <tt>/etc/pam.conf</tt>. + +The syntax of each file in <tt>/etc/pam.d/</tt> is similar to that of +the <tt>/etc/pam.conf</tt> file and is made up of lines of the +following form: +<tscreen> +<verb> +module-type control-flag module-path arguments +</verb> +</tscreen> +The only difference being that the <tt>service-name</tt> is not +present. The service-name is of course the name of the given +configuration file. For example, <tt>/etc/pam.d/login</tt> contains +the configuration for the <em>login</em> service. + +<p> +This method of configuration has a number of advantages over the +single file approach. We list them here to assist the reader in +deciding which scheme to adopt: + +<p> +<itemize> + +<item>A lower chance of misconfiguring an application. There is one +less field to mis-type when editing the configuration files by hand. + +<item>Easier to maintain. One application may be reconfigured without +risk of interfering with other applications on the system. + +<item>It is possible to symbolically link different services +configuration files to a single file. This makes it easier to keep the +system policy for access consistent across different applications. +(It should be noted, to conserve space, it is equally possible to +<em>hard</em> link a number of configuration files. However, care +should be taken when administering this arrangement as editing a hard +linked file is likely to break the link.) + +<item>A potential for quicker configuration file parsing. Only the +relevant entries are parsed when a service gets bound to its modules. + +<item>It is possible to limit read access to individual <bf/Linux-PAM/ +configuration files using the file protections of the filesystem. + +<item>Package management becomes simpler. Every time a new +application is installed, it can be accompanied by an +<tt>/etc/pam.d/</tt><em>xxxxxx</em> file. + +</itemize> + +<sect1>Generic optional arguments + +<p> +The following are optional arguments which are likely to be understood +by any module. Arguments (including these) are in general +<em/optional/. + +<p> +<descrip> +<tag><tt/debug/</tag> + +Use the <tt/syslog(3)/ call to log debugging information to the system +log files. + +<tag> <tt/no_warn/</tag> + +Instruct module to not give warning messages to the application. + +<tag> <tt/use_first_pass/</tag> + +The module should not prompt the user for a password. Instead, it +should obtain the previously typed password (from the preceding +<tt/auth/ module), and use that. If that doesn't work, then the user +will not be authenticated. (This option is intended for <tt/auth/ +and <tt/password/ modules only). + +<tag> <tt/try_first_pass/</tag> + +The module should attempt authentication with the previously typed +password (from the preceding <tt/auth/ module). If that doesn't work, +then the user is prompted for a password. (This option is intended for +<tt/auth/ modules only). + +<tag> <tt/use_mapped_pass/</tag> + +This argument is not currently supported by any of the modules in the +<bf/Linux-PAM/ distribution because of possible consequences +associated with U.S. encryption exporting restrictions. Within the +U.S., module developers are, of course, free to implement it (as are +developers in other countries). For compatibility reasons we describe +its use as suggested in the <bf/DCE-RFC 86.0/, see section <ref +id="see-also-sec" name="bibliography"> for a pointer to this document. + +<p> +The <tt/use_mapped_pass/ argument instructs the module to take the +clear text authentication token entered by a previous module (that +requests such a token) and use it to generate an encryption/decryption +key with which to safely store/retrieve the authentication token +required for this module. In this way the user can enter a single +authentication token and be quietly authenticated by a number of +stacked modules. Obviously a convenient feature that necessarily +requires some reliably strong encryption to make it secure. +This argument is intended for the <tt/auth/ and <tt/password/ module +types only. + +<tag><tt/expose_account/</tag> + +<p> +In general the leakage of some information about user accounts is not +a secure policy for modules to adopt. Sometimes information such as +users names or home directories, or preferred shell, can be used to +attack a user's account. In some circumstances, however, this sort of +information is not deemed a threat: displaying a user's full name when +asking them for a password in a secured environment could also be +called being 'friendly'. The <tt/expose_account/ argument is a +standard module argument to encourage a module to be less discrete +about account information as it is deemed appropriate by the local +administrator. + +</descrip> + +<sect1>Example configuration file entries + +<p> +In this section, we give some examples of entries that can be present +in the <bf/Linux-PAM/ configuration file. As a first attempt at +configuring your system you could do worse than to implement these. + +<sect2>Default policy + +<p> +If a system is to be considered secure, it had better have a +reasonably secure `<tt/OTHER/' entry. The following is a paranoid +setting (which is not a bad place to start!): +<tscreen> +<verb> +# +# default; deny access +# +OTHER auth required pam_deny.so +OTHER account required pam_deny.so +OTHER password required pam_deny.so +OTHER session required pam_deny.so +</verb> +</tscreen> +Whilst fundamentally a secure default, this is not very sympathetic to +a misconfigured system. For example, such a system is vulnerable to +locking everyone out should the rest of the file become badly written. + +<p> +The module <tt/pam_deny/ (documented in a later section) is not very +sophisticated. For example, it logs no information when it is invoked +so unless the users of a system contact the administrator when failing +to execute a service application, the administrator may go for a long +while in ignorance of the fact that his system is misconfigured. + +<p> +The addition of the following line before those in the above example +would provide a suitable warning to the administrator. +<tscreen> +<verb> +# +# default; wake up! This application is not configured +# +OTHER auth required pam_warn.so +OTHER password required pam_warn.so +</verb> +</tscreen> +Having two ``<tt/OTHER auth/'' lines is an example of stacking. + +<p> +On a system that uses the <tt>/etc/pam.d/</tt> configuration, the +corresponding default setup would be achieved with the following file: +<tscreen> +<verb> +# +# default configuration: /etc/pam.d/other +# +auth required pam_warn.so +auth required pam_deny.so +account required pam_deny.so +password required pam_warn.so +password required pam_deny.so +session required pam_deny.so +</verb> +</tscreen> +This is the only explicit example we give for an <tt>/etc/pam.d/</tt> +file. In general, it should be clear how to transpose the remaining +examples to this configuration scheme. + +<p> +On a less sensitive computer, one on which the system administrator +wishes to remain ignorant of much of the power of <tt/Linux-PAM/, the +following selection of lines (in <tt>/etc/pam.conf</tt>) is likely to +mimic the historically familiar Linux setup. +<tscreen> +<verb> +# +# default; standard UN*X access +# +OTHER auth required pam_unix.so +OTHER account required pam_unix.so +OTHER password required pam_unix.so +OTHER session required pam_unix.so +</verb> +</tscreen> +In general this will provide a starting place for most applications. +Unfortunately, most is not all. One application that might require +additional lines is <em/ftpd/ if you wish to enable +<em/anonymous-ftp/. + +<p> +To enable anonymous-ftp, the following lines might be used to replace +the default (<tt/OTHER/) ones. (<bf/*WARNING*/ as of 1996/12/28 this +does not work correctly with any ftpd. Consequently, this description +may be subject to change or the application will be fixed.) +<tscreen> +<verb> +# +# ftpd; add ftp-specifics. These lines enable anonymous ftp over +# standard UN*X access (the listfile entry blocks access to +# users listed in /etc/ftpusers) +# +ftpd auth sufficient pam_ftp.so +ftpd auth required pam_unix_auth.so use_first_pass +ftpd auth required pam_listfile.so \ + onerr=succeed item=user sense=deny file=/etc/ftpusers +</verb> +</tscreen> +Note, the second line is necessary since the default entries are +ignored by a service application (here <em/ftpd/) if there are +<em/any/ entries in <tt>/etc/pam.conf</tt> for that specified service. +Again, this is an example of authentication module stacking. Note the +use of the <tt/sufficient/ control-flag. It says that ``if this module +authenticates the user, ignore the subsequent <tt/auth/ +modules''. Also note the use of the ``<tt/use_first_pass/'' +module-argument, this instructs the UN*X authentication module that it +is not to prompt for a password but rely on one already having been +obtained by the <tt/pam_ftp/ module. + +<sect>Security issues of Linux-PAM + +<p> +This section will discuss good practices for using PAM in a secure +manner. <em>It is currently sadly lacking...suggestions are +welcome!</em> + +<sect1>If something goes wrong + +<p> +<bf/Linux-PAM/ has the potential to seriously change the security of +your system. You can choose to have no security or absolute security +(no access permitted). In general, <bf/Linux-PAM/ errs towards the +latter. Any number of configuration errors can dissable access to +your system partially, or completely. + +<p> +The most dramatic problem that is likely to be encountered when +configuring <bf/Linux-PAM/ is that of <em>deleting</em> the +configuration file(s): <tt>/etc/pam.d/*</tt> and/or +<tt>/etc/pam.conf</tt>. This will lock you out of your own system! + +<p> +To recover, your best bet is to reboot the system in single user mode +and set about correcting things from there. The following has been +<em>adapted</em> from a life-saving email on the subject from David +Wood: +<verb> +> What the hell do I do now? + +OK, don't panic. The first thing you have to realize is that +this happens to 50% of users who ever do anything with PAM. +It happened here, not once, not twice, but three times, all +different, and in the end, the solution was the same every +time. + +First, I hope you installed LILO with a delay. If you can, +reboot, hit shift or tab or something and type: + + LILO boot: linux single + +(Replace 'linux' with 'name-of-your-normal-linux-image'). +This will let you in without logging in. Ever wondered how +easy it is to break into a linux machine from the console? +Now you know. + +If you can't do that, then get yourself a bootkernel floppy +and a root disk a-la slackware's rescue.gz. (Red Hat's +installation disks can be used in this mode too.) + +In either case, the point is to get back your root prompt. + +Second, I'm going to assume that you haven't completely +nuked your pam installation - just your configuration files. +Here's how you make your configs nice again: + + cd /etc + mv pam.conf pam.conf.orig + mv pam.d pam.d.orig + mkdir pam.d + cd pam.d + +and then use vi to create a file called "other" in this +directory. It should contain the following four lines: + + auth required pam_unix.so + account required pam_unix.so + password required pam_unix.so + session required pam_unix.so + +Now you have the simplest possible PAM configuration that +will work the way you're used to. Everything should +magically start to work again. Try it out by hitting ALT-F2 +and logging in on another virtual console. If it doesn't +work, you have bigger problems, or you've mistyped +something. One of the wonders of this system (seriously, +perhaps) is that if you mistype anything in the conf files, +you usually get no error reporting of any kind on the +console - just some entries in the log file. So look there! +(Try 'tail /var/log/messages'.) + +From here you can go back and get a real configuration +going, hopefully after you've tested it first on a machine +you don't care about screwing up. :/ + +Some pointers (to make everything "right" with Red Hat...): + + Install the newest pam, pamconfig, and pwdb from the + redhat current directory, and do it all on the same + command line with rpm... + + rpm -Uvh [maybe --force too] pam-* pamconfig-* pwdb-* + + Then make sure you install (or reinstall) the newest + version of libc, util-linux, wuftp, and NetKit. For + kicks you might try installing the newest versions of + the affected x apps, like xlock, but I haven't gotten + those to work at all yet. + +</verb> + +<sect1>Avoid having a weak `other' configuration + +<p> +It is not a good thing to have a weak default (<tt/OTHER/) entry. +This service is the default configuration for all PAM aware +applications and if it is weak, your system is likely to be vulnerable +to attack. + +<p> +Here is a sample "other" configuration file. The <em/pam_deny/ module will +deny access and the <em/pam_warn/ module will send a syslog message to +<tt/auth.notice/: + +<p> +<tscreen> +<verb> +# +# The PAM configuration file for the `other' service +# +auth required pam_deny.so +auth required pam_warn.so +account required pam_deny.so +account required pam_warn.so +password required pam_deny.so +password required pam_warn.so +session required pam_deny.so +session required pam_warn.so +</verb> +</tscreen> + +<sect>A reference guide for available modules + +<p> +Here, we collect together some descriptions of the various modules +available for <bf/Linux-PAM/. In general these modules should be +freely available. Where this is not the case, it will be indicated. + +<p> +Also please note the comments contained in the section <ref +id="text-conventions" name="on text conventions above"> when copying +the examples listed below. + +<!-- insert-file MODULES-SGML --> + +<sect>Files + +<p><descrip> + +<tag><tt>/lib/libpam.so.*</tt></tag> + +the shared library providing applications with access to +<bf/Linux-PAM/. + +<tag><tt>/etc/pam.conf</tt></tag> + +the <bf/Linux-PAM/ configuration file. + +<tag><tt>/lib/security/pam_*.so</tt></tag> + +the primary location for <bf/Linux-PAM/ dynamically loadable object +files; the modules. + +</descrip> + +<sect>See also<label id="see-also-sec"> + +<p><itemize> + +<item>The <bf/Linux-PAM/ Application Writers' Guide. + +<item>The <bf/Linux-PAM/ Module Writers' Guide. + +<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH +PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request +For Comments 86.0, October 1995. See this url: +<tt><htmlurl +url="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz" +name="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz"></tt> + +</itemize> + +<sect>Notes + +<p> +I intend to put development comments here... like ``at the moment +this isn't actually supported''. At release time what ever is in +this section will be placed in the Bugs section below! :) + +<p> +Are we going to be able to support the <tt/use_mapped_pass/ module +argument? Anyone know a cheap (free) good lawyer?! + +<p> +<itemize> +<item> +This issue may go away, as Sun have investigated adding a new +management group for mappings. In this way, libpam would have mapping +modules that could securely store passwords using strong cryptography +and in such a way that they need not be distributed with Linux-PAM. +</itemize> + +<sect>Author/acknowledgments + +<p> +This document was written by Andrew G. Morgan (morgan@kernel.org) +with many contributions from +<!-- insert-file CREDITS --> + +<p> +Thanks are also due to Sun Microsystems, especially to Vipin Samar and +Charlie Lai for their advice. At an early stage in the development of +<bf/Linux-PAM/, Sun graciously made the documentation for their +implementation of PAM available. This act greatly accelerated the +development of <bf/Linux-PAM/. + +<sect>Bugs/omissions + +<p> +More PAM modules are being developed all the time. It is unlikely that +this document will ever be truely up to date! + +<p> +This manual is unfinished. Only a partial list of people is credited +for all the good work they have done. + +<sect>Copyright information for this document + +<p> +Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. +<newline> +Email: <tt><morgan@kernel.org></tt> + +<p> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +<p> +<itemize> + +<item> +1. Redistributions of source code must retain the above copyright + notice, and the entire permission notice in its entirety, + including the disclaimer of warranties. + +<item> +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +<item> +3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +</itemize> + +<p> +<bf/Alternatively/, this product may be distributed under the terms of +the GNU General Public License (GPL), in which case the provisions of +the GNU GPL are required <bf/instead of/ the above restrictions. +(This clause is necessary due to a potential bad interaction between +the GNU GPL and the restrictions contained in a BSD-style copyright.) + +<p> +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +<p> +<tt>$Id: pam_source.sgml,v 1.1.1.2 2002/09/15 20:08:25 hartmans Exp $</tt> + +</article> diff --git a/Linux-PAM/doc/pdf/README b/Linux-PAM/doc/pdf/README new file mode 100644 index 00000000..6a2f085e --- /dev/null +++ b/Linux-PAM/doc/pdf/README @@ -0,0 +1,3 @@ +$Id: README,v 1.1.1.1 2002/09/15 20:08:34 hartmans Exp $ + +a directory for PDF versions of the documentation diff --git a/Linux-PAM/doc/ps/README b/Linux-PAM/doc/ps/README new file mode 100644 index 00000000..5f7d2f34 --- /dev/null +++ b/Linux-PAM/doc/ps/README @@ -0,0 +1,3 @@ +$Id: README,v 1.1.1.2 2002/09/15 20:08:34 hartmans Exp $ + +this is the directory for the PostScript documentation diff --git a/Linux-PAM/doc/specs/draft-morgan-pam.raw b/Linux-PAM/doc/specs/draft-morgan-pam.raw new file mode 100644 index 00000000..cd829a17 --- /dev/null +++ b/Linux-PAM/doc/specs/draft-morgan-pam.raw @@ -0,0 +1,764 @@ +Open-PAM working group ## A.G. Morgan +Internet Draft: ## Dec 8, 2001 +Document: draft-morgan-pam-08.txt ## +Expires: June 8, 2002 ## +Obsoletes: draft-morgan-pam-07.txt## + +## Pluggable Authentication Modules (PAM) ## + +#$ Status of this memo + +This document is a draft specification. Its contents are subject to +change with revision. The latest version of this draft may be obtained +from here: + + http://www.kernel.org/pub/linux/libs/pam/pre/doc/ + +As + + Linux-PAM-'version'-docs.tar.gz + +It is also contained in the Linux-PAM tar ball. + +#$ Abstract + +This document is concerned with the definition of a general +infrastructure for module based authentication. The infrastructure is +named Pluggable Authentication Modules (PAM for short). + +#$ Introduction + +Computers are tools. They provide services to people and other +computers (collectively we shall call these _users_ entities). In +order to provide convenient, reliable and individual service to +different entities, it is common for entities to be labelled. Having +defined a label as referring to a some specific entity, the label is +used for the purpose of protecting and allocating data resources. + +All modern operating systems have a notion of labelled entities and +all modern operating systems face a common problem: how to +authenticate the association of a predefined label with applicant +entities. + +There are as many authentication methods as one might care to count. +None of them are perfect and none of them are invulnerable. In +general, any given authentication method becomes weaker over time. It +is common then for new authentication methods to be developed in +response to newly discovered weaknesses in the old authentication +methods. + +The problem with inventing new authentication methods is the fact that +old applications do not support them. This contributes to an inertia +that discourages the overhaul of weakly protected systems. Another +problem is that individuals (people) are frequently powerless to layer +the protective authentication around their systems. They are forced +to rely on single (lowest common denominator) authentication schemes +even in situations where this is far from appropriate. + +PAM, as discussed in this document, is a generalization of the +approach first introduced in [#$R#{OSF_RFC_PAM}]. In short, it is a +general framework of interfaces that abstract the process of +authentication. With PAM, a service provider can custom protect +individual services to the level that they deem is appropriate. + +PAM has nothing explicit to say about transport layer encryption. +Within the context of this document encryption and/or compression of +data exchanges are application specific (strictly between client and +server) and orthogonal to the process of authentication. + +#$ Definitions + +Here we pose the authentication problem as one of configuring defined +interfaces between two entities. + +#$$#{players} Players in the authentication process + +PAM reserves the following words to specify unique entities in the +authentication process: + + applicant + the entity (user) initiating an application for service + [PAM associates the PAM_RUSER _item_ with this requesting user]. + + arbitrator + the entity (user) under whose identity the service application + is negotiated and with whose authority service is granted. + + user + the entity (user) whose identity is being authenticated + [PAM associates the PAM_USER _item_ with this identity]. + + server + the application that provides service, or acts as an + authenticated gateway to the requested service. This + application is completely responsible for the server end of + the transport layer connecting the server to the client. + PAM makes no assumptions about how data is encapsulated for + exchanges between the server and the client, only that full + octet sequences can be freely exchanged without corruption. + + client + application providing the direct/primary interface to + applicant. This application is completely responsible + for the client end of the transport layer connecting the + server to the client. PAM makes no assumptions about how data + is encapsulated for exchanges between the server and the + client, only that full octet sequences can be freely + exchanged without corruption. + + module + authentication binary that provides server-side support for + some (arbitrary) authentication method. + + agent + authentication binary that provides client-side support for + some (arbitrary) authentication method. + +Here is a diagram to help orient the reader: + +## +-------+ +--------+ ## +## . . . . .| agent | .| module | ## +## . +-------+ .+--------+ ## +## V | . | ## +## . | V | ## +## +---------+ +-------+ . +------+ ## +## | | |libpamc| . |libpam| ## +## | | +-------+ . +------+ ## +## |applicant| | . | ## +## | | +--------+ +----------+ ## +## | |---| client |-----------| server | ## +## +---------+ +--------+ +----------+ ## + +Solid lines connecting the boxes represent two-way interaction. The +dotted-directed lines indicate an optional connection beteween the +plugin module (agent) and the server (applicant). In the case of the +module, this represents the module invoking the 'conversation' +callback function provided to libpam by the server application when it +inititializes the libpam library. In the case of the agent, this may +be some out-of-PAM API interaction (for example directly displaying a +dialog box under X). + +#$$ Defined Data Types + +In this draft, we define two composite data types, the text string and +the binary prompt. They are the data types used to communicate +authentication requests and responses. + +#$$$#{text_string} text string + +The text string is a simple sequence of non-NUL (NUL = 0x00) +octets. Terminated with a single NUL (0x00) octet. The character set +employed in the octet sequence may be negotiated out of band, but +defaults to utf-8. + +## --------------------------- ## +## [ character data | NUL ] ## +## [ octet sequence | 0x00 ] ## +## --------------------------- ## + +Within the rest of this text, PAM text strings are delimited with a +pair of double quotes. Example, "this" = {'t';'h';'i';'s';0x00}. + +#$$$#{binary_prompt} binary prompt + +A binary prompt consists of a stream of octets arranged as follows: + +## ---------------------------------------- ## +## [ u32 | u8 | (length-5 octets) ] ## +## [ length | control | data ] ## +## ---------------------------------------- ## + +That is, a 32-bit unsigned integer in network byte order, a single +unsigned byte of control information and a sequence of octets of +length (length-5). The composition of the _data_ is context dependent +but is generally not a concern for either the server or the client. It +is very much the concern of modules and agents. + +For purposes of interoperability, we define the following control +characters as legal. + +## value symbol description ## +## ------------------------------------------------- ## +## 0x01 PAM_BPC_OK - continuation packet ## +## 0x02 PAM_BPC_SELECT - initialization packet ## +## 0x03 PAM_BPC_DONE - termination packet ## +## 0x04 PAM_BPC_FAIL - unable to execute ## + +The following control characters are only legal for exchanges between +an agent and a client (it is the responsibility of the client to +enforce this rule in the face of a rogue server): + +## 0x41 PAM_BPC_GETENV - obtain client env.var ## +## 0x42 PAM_BPC_PUTENV - set client env.var ## +## 0x43 PAM_BPC_TEXT - display message ## +## 0x44 PAM_BPC_ERROR - display error message ## +## 0x45 PAM_BPC_PROMPT - echo'd text prompt ## +## 0x46 PAM_BPC_PASS - non-echo'd text prompt ## +## 0x46 PAM_BPC_STATUS - ping all active clients## +## 0x47 PAM_BPC_ABORT - please abort session ## + +Note, length is always equal to the total length of the binary +prompt and represented by a network ordered unsigned 32 bit integer. + +#$$$$#{agent_ids} PAM_BPC_SELECT binary prompts + +Binary prompts of control type PAM_BPC_SELECT have a defined +data part. It is composed of three elements: + + {agent_id;'/';data} + +The agent_id is a sequence of characters satisfying the following +regexp: + + /^[a-z0-9\_]+(@[a-z0-9\_.]+)?$/ + +and has a specific form for each independent agent. + +o Agent_ids that do not contain an at-sign (@) are to be considered as + representing some authentication mode that is a "public + standard" see reference [#$R#{PAM_STD_AGENTIDS}]. Registered names + MUST NOT contain an at-sign (@). + +o Anyone can define additional agents by using names in the format + name@domainname, e.g. "ouragent@example.com". The part following + the at-sign MUST be a valid fully qualified internet domain name + [RFC-1034] controlled by the person or organization defining the + name. (Said another way, if you control the email address that + your agent has as an identifier, they you are entitled to use + this identifier.) It is up to each domain how it manages its local + namespace. + +The '/' character is a mandatory delimiter, indicating the end of the +agent_id. The trailing data is of a format specific to the agent with +the given agent_id. + + +#$$ Special cases + +In a previous section (#{players}) we identified the most general +selection of authentication participants. In the case of network +authentication, it is straightforward to ascribe identities to the +defined participants. However, there are also special (less general) +cases that we recognize here. + +The primary authentication step, when a user is directly introduced +into a computer system (log's on to a workstation) is a special case. +In this situation, the client and the server are generally one +application. Before authenticating such a user, the applicant is +formally unknown: PAM_RUSER is NULL. + +Some client-server implementations (telnet for example) provide +effective full tty connections. In these cases, the four simple text +string prompting cases (see below) can be handled as in the primary +login step. In other words, the server absorbs most of the overhead of +propagating authentication messages. In these cases, there needs to be +special client/server support for handling binary prompts. + +In some circumstances, a legacy network transfer protocol can carry +authentication information. In such cases, a desire to support legacy +clients (with no client-side support for PAM) will neccessitate the +'hardcoding' of an agent protocol into the server application. Whilst +against the spirit of PAM, this special casing can be managed by the +server's 'conversation function' (see below). The guiding principle +when implementing such support is for the application developer to +relegate the authentication process to the PAM module -- simply +performing a transcription of data from binary-prompt to legacy +network 'packet' and visa-versa for propagating replies back to the +driving PAM module. A common case of this is with network protocols +that define an initialization packet of "user+password". In such cases +one should attempt to support the "userpass" agent-id and its defined +protocol. + +#$ Defined interfaces for information flow + +Here, we discuss the information exchange interfaces between the +players in the authentication process. It should be understood that +the server side is responsible for driving the authentication of the +applicant. Notably, every request received by the client from the +server must be matched with a single response from the client to the +server. + +#$$#{applicant_client} Applicant <-> client + +Once the client is invoked, requests to the applicant entity are +initiated by the client application. General clients are able to make +the following requests directly to an applicant: + + echo text string + echo error text string + prompt with text string for echo'd text string input + prompt with text string for concealed text string input + +the nature of the interface provided by the client for the benefit of +the applicant entity is client specific and not defined by PAM. + +#$$#{client_agent} Client <-> agent + +In general, authentication schemes require more modes of exchange than +the four defined in the previous section (#{applicant_client}). This +provides a role for client-loadable agents. The client and agent +exchange binary-messages that can have one of the following forms: + + client -> agent + binary prompt agent expecting binary prompt reply to client + + agent -> client + binary prompt reply from agent to clients binary prompt + +Following the acceptance of a binary prompt by the agent, the agent +may attempt to exchange information with the client before returning +its binary prompt reply. Permitted exchanges are binary prompts of the +following types: + + agent -> client + set environment variable (A) + get environment variable (B) + echo text string (C) + echo error text string (D) + prompt for echo'd text string input (E) + prompt for concealed text string input (F) + +In response to these prompts, the client must legitimately respond +with a corresponding binary prompt reply. We list a complete set of +example exchanges, including each type of legitimate response (passes +and a single fail): + +## Type | Agent request | Client response ## +## --------------------------------------------------------------- ## +## (A) | {13;PAM_BPC_PUTENV;"FOO=BAR"} | {5;PAM_BPC_OK;} ## +## | {10;PAM_BPC_PUTENV;"FOO="} | {5;PAM_BPC_OK;} ## +## | {9;PAM_BPC_PUTENV;"FOO"} (*) | {5;PAM_BPC_OK;} ## +## | {9;PAM_BPC_PUTENV;"BAR"} (*) | {5;PAM_BPC_FAIL;} ## +## --------------------------------------------------------------- ## +## (B) | {10;PAM_BPC_GETENV;"TERM"} | {11;PAM_BPC_OK;"vt100"} ## +## | {9;PAM_BPC_GETENV;"FOO"} | {5;PAM_BPC_FAIL;} ## +## --------------------------------------------------------------- ## +## (C) | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_OK;} ## +## | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_FAIL;} ## +## --------------------------------------------------------------- ## +## (D) | {11;PAM_BPC_ERROR;"ouch!"} | {5;PAM_BPC_OK;} ## +## | {11;PAM_BPC_ERROR;"ouch!"} | {5;PAM_BPC_FAIL;} ## +## --------------------------------------------------------------- ## +## (E) | {13;PAM_BPC_PROMPT;"login: "} | {9;PAM_BPC_OK;"joe"} ## +## | {13;PAM_BPC_PROMPT;"login: "} | {6;PAM_BPC_OK;""} ## +## | {13;PAM_BPC_PROMPT;"login: "} | {5;PAM_BPC_FAIL;} ## +## --------------------------------------------------------------- ## +## (F) | {16;PAM_BPC_PASS;"password: "} | {9;PAM_BPC_OK;"XYZ"} ## +## | {16;PAM_BPC_PASS;"password: "} | {6;PAM_BPC_OK;""} ## +## | {16;PAM_BPC_PASS;"password: "} | {5;PAM_BPC_FAIL;} ## + +(*) Used to attempt the removal of a pre-existing environment +variable. + +#$$ Client <-> server + +Once the client has established a connection with the server (the +nature of the transport protocol is not specified by PAM), the server +is responsible for driving the authentication process. + +General servers can request the following from the client: + + (to be forwarded by the client to the applicant) + echo text string + echo error text string + prompt for echo'd text string response + prompt for concealed text string response + + (to be forwarded by the client to the appropriate agent) + binary prompt for a binary prompt response + +Client side agents are required to process binary prompts. The +agents' binary prompt responses are returned to the server. + +#$$ Server <-> module + +Modules drive the authentication process. The server provides a +conversation function with which it encapsulates module-generated +requests and exchanges them with the client. Every message sent by a +module should be acknowledged. + +General conversation functions can support the following five +conversation requests: + + echo text string + echo error string + prompt for echo'd text string response + prompt for concealed text string response + binary prompt for binary prompt response + +The server is responsible for redirecting these requests to the +client. + +#$ C API for application interfaces (client and server) + +#$$ Applicant <-> client + +No API is defined for this interface. The interface is considered to +be specific to the client application. Example applications include +terminal login, (X)windows login, machine file transfer applications. + +All that is important is that the client application is able to +present the applicant with textual output and to receive textual +input from the applicant. The forms of textual exchange are listed +in an earlier section (#{applicant_client}). Other methods of +data input/output are better suited to being handled via an +authentication agent. + +#$$ Client <-> agent + +The client makes use of a general API for communicating with +agents. The client is not required to communicate directly with +available agents, instead a layer of abstraction (in the form of a +library: libpamc) takes care of loading and maintaining communication +with all requested agents. This layer of abstraction will choose which +agents to interact with based on the content of binary prompts it +receives that have the control type PAM_BPC_SELECT. + +#$$$ Client <-> libpamc + +#$$$$ Compilation information + +The C-header file provided for client-agent abstraction is included +with the following source line: + + \#include <security/pam_client.h> + +The library providing the corresponding client-agent abstraction +functions is, libpamc. + + cc .... -lpamc + +#$$$$ Initializing libpamc + +The libpamc library is initialized with a call to the following +function: + + pamc_handle_t pamc_start(void); + +This function is responsible for configuring the library and +registering the location of available agents. The location of the +available agents on the system is implementation specific. + +pamc_start() function returns NULL on failure. Otherwise, the return +value is a pointer to an opaque data type which provides a handle to +the libpamc library. On systems where threading is available, the +libpamc libraray is thread safe provided a single (pamc_handler_t *) +is used by each thread. + +#$$$$ Client (Applicant) selection of agents + +For the purpose of applicant and client review of available agents, +the following function is provided. + + char **pamc_list_agents(pamc_handle_t pch); + +This returns a list of pointers to the agent_id's of the agents which +are available on the system. The list is terminated by a NULL pointer. +It is the clients responsibility to free this memory area by calling +free() on each agent id and the block of agent_id pointers in the +result. + +PAM represents a server-driven authentication model, so by default +any available agent may be invoked in the authentication process. + +#$$$$$ Client demands agent + +If the client requires that a specific authentication agent is +satisfied during the authentication process, then the client should +call the following function, immediately after obtaining a +pamc_handle_t from pamc_start(). + + int pamc_load(pamc_handle_t pch, const char *agent_id); + +agent_id is a PAM text string (see section #{agent_ids}) and is not +suffixed with a '/' delimiter. The return value for this function is: + + PAM_BPC_TRUE - agent located and loaded. + PAM_BPC_FALSE - agent is not available. + +Note, although the agent is loaded, no data is fed to it. The agent's +opportunity to inform the client that it does not trust the server is +when the agent is shutdown. + +#$$$$$ Client marks agent as unusable + +The applicant might prefer that a named agent is marked as not +available. To do this, the client would invoke the following function +immediately after obtaining a pamc_handle_t from pam_start(). + + int pamc_disable(pamc_handle_t pch, const char *agent_id); + +here agent_id is a PAM text string containing an agent_id (section +#{agent_ids}). + +The return value for this function is: + + PAM_BPC_TRUE - agent is disabled. This is the response + independent of whether the agent is locally + available. + + PAM_BPC_FALSE - agent cannot be disabled (this may be because + it has already been invoked). + +#$$$$ Allocating and manipulating binary prompts + +All conversation between an client and an agent takes place with +respect to binary prompts. A binary prompt (see section #{binary_prompt}), is +obtained, resized and deleted via the following C-macro: + + CREATION of a binary prompt with control X1 and data length Y1: + + pamc_bp_t prompt = NULL; + PAM_BP_RENEW(&prompt, X1, Y1); + + REPLACEMENT of a binary prompt with a control X2 and data length Y2: + + PAM_BP_RENEW(&prompt, X2, Y2); + + DELETION of a binary prompt (the referenced prompt is scrubbed): + + PAM_BP_RENEW(&prompt, 0, 0); + +Note, the PAM_BP_RENEW macro always overwrites any prompt that you +call it with, deleting and liberating the old contents in a secure +fashion. Also note that PAM_BP_RENEW, when returning a prompt of data +size Y1>0, will always append a '\0' byte to the end of the prompt (at +data offset Y1). It is thus, by definition, acceptable to treat the +data contents of a binary packet as a text string (see #{text_string}). + + FILLING a binary prompt from a memory pointer U1 from offset O1 of + length L1: + + PAM_BP_FILL(prompt, O1, L1, U1); + + the CONTROL type for the packet can be obtained as follows: + + control = PAM_PB_CONTROL(prompt); + + the LENGTH of a data within the prompt (_excluding_ its header + information) can be obtained as follows: + + length = PAM_BP_LENGTH(prompt); + + the total SIZE of the prompt (_including_ its header information) + can be obtained as follows: + + size = PAM_BP_SIZE(prompt); + + EXTRACTING data from a binary prompt from offset O2 of length L2 to + a memory pointer U2: + + PAM_BP_EXTRACT(prompt, O2, L2, U2); + + If you require direct access to the raw prompt DATA, you should use + the following macro: + + __u8 *raw_data = PAM_BP_DATA(prompt); + +#$$$$ Client<->agent conversations + +All exchanges of binary prompts with agents are handled with the +single function: + + int pamc_converse(pamc_handle_t *pch, pamc_bp_t *prompt_p); + +The return value for pamc_converse(...) is PAM_BPC_TRUE when there is +a response packet and PAM_BPC_FALSE when the client is unable to +handle the request represented by the original prompt. In this latter +case, *prompt_p is set to NULL. + +This function takes a binary prompt and returns a replacement binary +prompt that is either a request from an agent to be acted upon by the +client or the 'result' which should be forwarded to the server. In the +former case, the following macro will return 1 (PAM_BPC_TRUE) and in +all other cases, 0 (PAM_BPC_FALSE): + + PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt) + +Note, all non-NULL binary prompts returned by pamc_converse(...), are +terminated with a '\0', even when the full length of the prompt (as +returned by the agent) does not contain this delimiter. This is a +defined property of the PAM_BP_RENEW macro, and can be relied upon. + +Important security note: in certain implementations, agents are +implemented by executable binaries, which are transparently loaded and +managed by the PAM client library. To ensure there is never a leakage +of elevated privilege to an unprivileged agent, the client application +should go to some effort to lower its level of privilege. It remains +the responsibility of the applicant and the client to ensure that it +is not compromised by a rogue agent. + +#$$$$ Status of agents + + int pamc_status(pamc_handle_t *pch, pamc_bp_t *prompt_p); + +At any time, the client may ping all active agents for their status +(with a PAM_BPC_STATUS binary prompt). If any agent replies with +PAM_BPC_ABORT, the client is responsible for terminating the +connection to the server and then terminating all agents with a call +to pamc_end(). In such cases, the return value of pamc_status() is +PAM_BPC_FALSE. + +If the return status of pamc_status() is PAM_BPC_TRUE and *prompt_p is +non-NULL, then an agent is requesting access to a server module. + +XXX - how this information gets propagated to the server, and + ultimately to the server's module is yet to be determined. + +#$$$$ Termination of agents + +When closing the authentication session and severing the connection +between a client and a selection of agents, the following function is +used: + + int pamc_end(pamc_handle_t *pch); + +Following a call to pamc_end, the pamc_handle_t will be invalid. + +The return value for this function is one of the following: + + PAM_BPC_TRUE - all invoked agents are content with + authentication (the server is _not_ judged + _un_trustworthy by any agent) + + PAM_BPC_FALSE - one or more agents were unsatisfied at + being terminated. In general, the client + should terminate its connection to the + server and indicate to the applicant that + the server is untrusted. + +#$$$ libpamc <-> agents + +The agents are manipulated from within libpamc. Each agent is an +executable in its own right. This permits the agent to have access to +sensitive data not accessible directly from the client. The mode of +communication between libpamc and an agent is through a pair of +pipes. The agent reads binary prompts (section #{binary_prompt}) +through its standard input file descriptor and writes response (to the +server) binary prompts and instruction binary prompts (instructions +for the client) through its standard output file descriptor. + +#$$ Client <-> server + +This interface is concerned with the exchange of text and binary +prompts between the client application and the server application. No +API is provided for this as it is considered specific to the transport +protocol shared by the client and the server. + +#$$ Server <-> modules + +The server makes use of a general API for communicating with +modules. The client is not required to communicate directly with +available modules. By abstracting the authentication interface, it +becomes possible for the local administrator to make a run time +decision about the authentication method adopted by the server. + +#$$$ Functions and definitions available to servers and modules + +[This section will document the following functions + + pam_set_item() + pam_get_item() + pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec) + pam_get_env(pam_handle_t *pamh, const char *varname) + pam_strerror(pam_handle_t *pamh, int pam_errno) + +Event driven support (XXX work in progress) + + pam_register_event() - app or module associates an event poller/handler + pam_select_event() - query for any outstanding event and act on any +] + +#$$$ Server <-> libpam + +[This section will document the following pam_ calls: + + pam_start + pam_end + pam_authenticate (*) + pam_setcred + pam_acct_mgmt + pam_open_session + pam_close_session + pam_chauthtok (*) + +The asterisked functions may return PAM_INCOMPLETE. In such cases, the +application should be aware that the conversation function was called +and that it returned PAM_CONV_AGAIN to a module. The correct action +for the application to take in response to receiving PAM_INCOMPLETE, +is to acquire the replies so that the next time the conversation +function is called it will be able to provide the desired +responses. And then recall pam_authenticate (pam_chauthtok) with the +same arguments. Libpam will arrange that the module stack is resumed +from the module that returned before. This functionality is required +for programs whose user interface is maintained by an event loop. ] + +#$$$ libpam <-> modules + +[This section will document the following pam_ and pam_sm_ calls: + +functions provided by libpam + + pam_set_data + pam_get_data + +functions provided to libpam by each module + + groups: + AUTHENTICATION + pam_sm_authenticate + pam_sm_setcred + ACCOUNT + pam_sm_acct_mgmt + SESSION + pam_sm_open_session + pam_sm_close_session + AUTHENTICATION TOKEN MANAGEMENT + pam_sm_chauthtok +] + +#$$$ The conversation function + +The server application, as part of its initialization of libpam, +provides a conversation function for use by modules and libpam. The +purpose of the conversation function is to enable direct communication +to the applicant ultimately via the client and selected agents. + +[ this section will contain a definition for the conversation + function, the conversation structure (appdata etc), and legitimate + return codes for the application supplied function. + + PAM_SUCCESS - ok conversation completed + PAM_CONV_ERR - conversation failed + PAM_CONV_AGAIN - application needs control to complete conv + PAM_CONV_RECONSIDER - application believes module should check if + it still needs to converse for this info + ] + +#$ Security considerations + +This document is devoted to standardizing authentication +infrastructure: everything in this document has implications for +security. + +#$ Contact + +The email list for discussing issues related to this document is +<pam-list@redhat.com>. + +#$ References + +[#{OSF_RFC_PAM}] OSF RFC 86.0, "Unified Login with Pluggable Authentication + Modules (PAM)", October 1995 + +[#{PAM_STD_AGENTIDS}] Definitions for standard agents, "REGISTERED + AGENTS AND THEIR AGENT-ID'S", to be found here: + +## http://www.kernel.org/pub/linux/libs/pam/pre/doc/std-agent-ids.txt ## + +#$ Author's Address + +Andrew G. Morgan +Email: morgan@kernel.org + +## $Id: draft-morgan-pam.raw,v 1.1.1.2 2002/09/15 20:08:34 hartmans Exp $ ## diff --git a/Linux-PAM/doc/specs/formatter/Makefile b/Linux-PAM/doc/specs/formatter/Makefile new file mode 100644 index 00000000..d73258d7 --- /dev/null +++ b/Linux-PAM/doc/specs/formatter/Makefile @@ -0,0 +1,16 @@ +LIBS=-lfl + +padout: parse.tab.o + $(CC) -o padout parse.tab.o $(LIBS) + +parse.tab.o: parse.tab.c lex.yy.c + $(CC) -c parse.tab.c + +parse.tab.c: parse.y + bison parse.y + +lex.yy.c: parse.lex + flex parse.lex + +clean: + rm -f parse.tab.o parse.tab.c lex.yy.c padout *~ core diff --git a/Linux-PAM/doc/specs/formatter/parse.lex b/Linux-PAM/doc/specs/formatter/parse.lex new file mode 100644 index 00000000..1d5c898e --- /dev/null +++ b/Linux-PAM/doc/specs/formatter/parse.lex @@ -0,0 +1,11 @@ +%% + +\#[\$]+[a-zA-Z]*(\=[0-9]+)? return NEW_COUNTER; +\#\{[a-zA-Z][a-zA-Z0-9\_]*\} return LABEL; +\# return NO_INDENT; +\#\# return RIGHT; +\\\# return HASH; +[^\n] return CHAR; +[\n] return NEWLINE; + +%% diff --git a/Linux-PAM/doc/specs/formatter/parse.y b/Linux-PAM/doc/specs/formatter/parse.y new file mode 100644 index 00000000..6da47d17 --- /dev/null +++ b/Linux-PAM/doc/specs/formatter/parse.y @@ -0,0 +1,293 @@ + +%{ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MAXLINE 1000 +#define INDENT_STRING " " +#define PAPER_WIDTH 74 + + int indent=0; + int line=1; + char *last_label=NULL; + + extern void yyerror(const char *x); + extern char *get_label(const char *label); + extern void set_label(const char *label, const char *target); + char *new_counter(const char *key); + +#include "lex.yy.c" + +%} + +%union { + int def; + char *string; +} + +%token NEW_COUNTER LABEL HASH CHAR NEWLINE NO_INDENT RIGHT +%type <string> stuff text + +%start doc + +%% + +doc: +| doc NEWLINE { + printf("\n"); + ++line; +} +| doc stuff NEWLINE { + if (strlen($2) > (PAPER_WIDTH-(indent ? strlen(INDENT_STRING):0))) { + yyerror("line too long"); + } + printf("%s%s\n", indent ? INDENT_STRING:"", $2); + free($2); + indent = 1; + ++line; +} +| doc stuff RIGHT stuff NEWLINE { + char fixed[PAPER_WIDTH+1]; + int len; + + len = PAPER_WIDTH-(strlen($2)+strlen($4)); + + if (len >= 0) { + memset(fixed, ' ', len); + fixed[len] = '\0'; + } else { + yyerror("line too wide"); + fixed[0] = '\0'; + } + printf("%s%s%s\n", $2, fixed, $4); + free($2); + free($4); + indent = 1; + ++line; +} +| doc stuff RIGHT stuff RIGHT stuff NEWLINE { + char fixed[PAPER_WIDTH+1]; + int len, l; + + len = PAPER_WIDTH-(strlen($2)+strlen($4)); + + if (len < 0) { + len = 0; + yyerror("line too wide"); + } + + l = len/2; + memset(fixed, ' ', l); + fixed[l] = '\0'; + printf("%s%s%s", $2, fixed, $4); + free($2); + free($4); + + l = (len+1)/2; + memset(fixed, ' ', l); + fixed[l] = '\0'; + printf("%s%s\n", fixed, $6); + free($6); + + indent = 1; + ++line; +} +| doc stuff RIGHT stuff RIGHT stuff NEWLINE { + char fixed[PAPER_WIDTH+1]; + int len, l; + + len = PAPER_WIDTH-(strlen($2)+strlen($4)); + + if (len < 0) { + len = 0; + yyerror("line too wide"); + } + + l = len/2; + memset(fixed, ' ', l); + fixed[l] = '\0'; + printf("%s%s%s", $2, fixed, $4); + free($2); + free($4); + + l = (len+1)/2; + memset(fixed, ' ', l); + fixed[l] = '\0'; + printf("%s%s\n", fixed, $6); + free($6); + + indent = 1; + ++line; +} +; + +stuff: { + $$ = strdup(""); +} +| stuff text { + $$ = malloc(strlen($1)+strlen($2)+1); + sprintf($$,"%s%s", $1, $2); + free($1); + free($2); +} +; + +text: CHAR { + $$ = strdup(yytext); +} +| text CHAR { + $$ = malloc(strlen($1)+2); + sprintf($$,"%s%s", $1, yytext); + free($1); +} +| NO_INDENT { + $$ = strdup(""); + indent = 0; +} +| HASH { + $$ = strdup("#"); +} +| LABEL { + if (($$ = get_label(yytext)) == NULL) { + set_label(yytext, last_label); + $$ = strdup(""); + } +} +| NEW_COUNTER { + $$ = new_counter(yytext); +} +; + +%% + +typedef struct node_s { + struct node_s *left, *right; + const char *key; + char *value; +} *node_t; + +node_t label_root = NULL; +node_t counter_root = NULL; + +const char *find_key(node_t root, const char *key) +{ + while (root) { + int cmp = strcmp(key, root->key); + + if (cmp > 0) { + root = root->right; + } else if (cmp) { + root = root->left; + } else { + return root->value; + } + } + return NULL; +} + +node_t set_key(node_t root, const char *key, const char *value) +{ + if (root) { + int cmp = strcmp(key, root->key); + if (cmp > 0) { + root->right = set_key(root->right, key, value); + } else if (cmp) { + root->left = set_key(root->left, key, value); + } else { + free(root->value); + root->value = strdup(value); + } + } else { + root = malloc(sizeof(struct node_s)); + root->right = root->left = NULL; + root->key = strdup(key); + root->value = strdup(value); + } + return root; +} + +void yyerror(const char *x) +{ + fprintf(stderr, "line %d: %s\n", line, x); +} + +char *get_label(const char *label) +{ + const char *found = find_key(label_root, label); + + if (found) { + return strdup(found); + } + return NULL; +} + +void set_label(const char *label, const char *target) +{ + if (target == NULL) { + yyerror("no hanging value for label"); + target = "<??>"; + } + label_root = set_key(label_root, label, target); +} + +char *new_counter(const char *key) +{ + int i=0, j, ndollars = 0; + const char *old; + char *new; + + if (key[i++] != '#') { + yyerror("bad index"); + return strdup("<???>"); + } + + while (key[i] == '$') { + ++ndollars; + ++i; + } + + key += i; + old = find_key(counter_root, key); + new = malloc(20*ndollars); + + if (old) { + for (j=0; ndollars > 1 && old[j]; ) { + if (old[j++] == '.' && --ndollars <= 0) { + break; + } + } + if (j) { + strncpy(new, old, j); + } + if (old[j]) { + i = atoi(old+j); + } else { + new[j++] = '.'; + i = 0; + } + } else { + j=0; + while (--ndollars > 0) { + new[j++] = '0'; + new[j++] = '.'; + } + i = 0; + } + new[j] = '\0'; + sprintf(new+j, "%d", ++i); + + counter_root = set_key(counter_root, key, new); + + if (last_label) { + free(last_label); + } + last_label = strdup(new); + + return new; +} + +main() +{ + yyparse(); +} diff --git a/Linux-PAM/doc/specs/rfc86.0.txt b/Linux-PAM/doc/specs/rfc86.0.txt new file mode 100644 index 00000000..6dd5e6ea --- /dev/null +++ b/Linux-PAM/doc/specs/rfc86.0.txt @@ -0,0 +1,1851 @@ + + + + + + + + + Open Software Foundation V. Samar (SunSoft) + Request For Comments: 86.0 R. Schemers (SunSoft) + October 1995 + + + + UNIFIED LOGIN WITH + PLUGGABLE AUTHENTICATION MODULES (PAM) + + + 1. INTRODUCTION + + Since low-level authentication mechanisms constantly evolve, it is + important to shield the high-level consumers of these mechanisms + (system-entry services and users) from such low-level changes. With + the Pluggable Authentication Module (PAM) framework, we can provide + pluggability for a variety of system-entry services -- not just + system authentication _per se_, but also for account, session and + password management. PAM's ability to _stack_ authentication modules + can be used to integrate `login' with different authentication + mechanisms such as RSA, DCE, and Kerberos, and thus unify login + mechanisms. The PAM framework can also provide easy integration of + smart cards into the system. + + Modular design and pluggability have become important for users who + want ease of use. In the PC hardware arena, no one wants to set the + interrupt vector numbers or resolve the addressing conflict between + various devices. In the software arena, people also want to be able + to replace components easily for easy customization, maintenance, and + upgrades. + + Authentication software deserves special attention because + authentication forms a very critical component of any secure computer + system. The authentication infrastructure and its components may + have to be modified or replaced either because some deficiencies have + been found in the current algorithms, or because sites want to + enforce a different security policy than what was provided by the + system vendor. The replacement and modification should be done in + such a way that the user is not affected by these changes. + + The solution has to address not just how the applications use the new + authentication mechanisms in a generic fashion, but also how the user + will be authenticated to these mechanisms in a generic way. The + former is addressed by GSS-API [Linn 93], while this RFC addresses + the later; these two efforts are complementary to each other. + + Since most system-entry services (for example, `login', `dtlogin', + `rlogin', `ftp', `rsh') may want to be independent of the specific + authentication mechanisms used by the machine, it is important that + there be a framework for _plugging_ in various mechanisms. This + requires that the system applications use a standard API to interact + + + + Samar, Schemers Page 1 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + with the authentication services. If these system-entry services + remain independent of the actual mechanism used on that machine, the + system administrator can install suitable authentication modules + without requiring changes to these applications. + + For any security system to be successful, it has to be easy to use. + In the case of authentication, the single most important ease-of-use + characteristic is that the user should not be required to learn about + various ways of authentication and remember multiple passwords. + Ideally, there should be one all-encompassing authentication system + where there is only one password, but for heterogeneous sites, + multiple authentication mechanisms have to co-exist. The problem of + integrating multiple authentication mechanisms such as Kerberos + [Steiner 88], RSA [Rivest 78], and Diffie-Hellman [Diffie 76, Taylor + 88], is also referred to as _integrated login_, or _unified login_ + problem. Even if the user has to use multiple authentication + mechanisms, the user should not be forced to type multiple passwords. + Furthermore, the user should be able to use the new network identity + without taking any further actions. The key here is in modular + integration of the network authentication technologies with `login' + and other system-entry services. + + In this RFC we discuss the architecture and design of pluggable + authentication modules. This design gives the capability to use + field-replaceable authentication modules along with unified login + capability. It thus provides for both _pluggability_ and _ease-of- + use_. + + The RFC is organized as follows. We first motivate the need for a + generic way to authenticate the user by various system-entry services + within the operating system. We describe the goals and constraints + of the design. This leads to the architecture, description of the + interfaces, and _stacking_ of modules to get unified login + functionality. We then describe our experience with the design, and + end with a description of future work. + + + 2. OVERVIEW OF IDENTIFICATION AND AUTHENTICATION MECHANISMS + + An identification and authentication ("I&A") mechanism is used to + establish a user's identity the system (i.e., to a local machine's + operating system) and to other principals on the network. On a + typical UNIX system, there are various ports of entry into the + system, such as `login', `dtlogin', `rlogin', `ftp', `rsh', `su', and + `telnet'. In all cases, the user has to be identified and + authenticated before granting appropriate access rights to the user. + The user identification and authentication for all these entry points + needs to be coordinated to ensure a secure system. + + In most of the current UNIX systems, the login mechanism is based + upon verification of the password using the modified DES algorithm. + + + + Samar, Schemers Page 2 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + The security of the implementation assumes that the password cannot + be guessed, and that the password does not go over the wire in the + clear. These assumptions, however, are not universally valid. + Various programs are now available freely on the Internet that can + run dictionary attack against the encrypted password. Further, some + of the network services (for example, `rlogin', `ftp', `telnet') send + the password over in clear, and there are "sniffer" programs freely + available to steal these passwords. The classical assumptions may be + acceptable on a trusted network, but in an open environment there is + a need to use more restrictive and stronger authentication + mechanisms. Examples of such mechanisms include Kerberos, RSA, + Diffie-Hellman, one-time password [Skey 94], and challenge-response + based smart card authentication systems. Since this list will + continue to evolve, it is important that the system-entry services do + not have hard-coded dependencies on any of these authentication + mechanisms. + + + 3. DESIGN GOALS + + The goals of the PAM framework are as follows: + + (a) The system administrator should be able to choose the default + authentication mechanism for the machine. This can range from + a simple password-based mechanism to a biometric or a smart + card based system. + + (b) It should be possible to configure the user authentication + mechanism on a per application basis. For example, a site may + require S/Key password authentication for `telnet' access, + while allowing machine `login' sessions with just UNIX password + authentication. + + (c) The framework should support the display requirements of the + applications. For example, for a graphical login session such + as `dtlogin', the user name and the password may have to be + entered in a new window. For networking system-entry + applications such as `ftp' and `telnet', the user name and + password has to be transmitted over the network to the client + machine. + + (d) It should be possible to configure multiple authentication + protocols for each of those applications. For example, one may + want the users to get authenticated by both Kerberos and RSA + authentication systems. + + (e) The system administrator should be able to _stack_ multiple + user authentication mechanisms such that the user is + authenticated with all authentication protocols without + retyping the password. + + + + + Samar, Schemers Page 3 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + (f) The architecture should allow for multiple passwords if + necessary to achieve higher security for users with specific + security requirements. + + (g) The system-entry services should not be required to change when + the underlying mechanism changes. This can be very useful for + third-party developers because they often do not have the + source code for these services. + + (h) The architecture should provide for a _pluggable_ model for + system authentication, as well as for other related tasks such + as password, account, and session management. + + (i) For backward-compatibility reasons, the PAM API should support + the authentication requirements of the current system-entry + services. + + There are certain issues that the PAM framework does not specifically + address: + + (a) We focus only on providing a generic scheme through which users + use passwords to establish their identities to the machine. + Once the identity is established, how the identity is + communicated to other interested parties is outside the scope + of this design. There are efforts underway at IETF [Linn 93] + to develop a Generic Security Services Application Interface + (GSSAPI) that can be used by applications for secure and + authenticated communication without knowing the underlying + mechanism. + + (b) The _single-signon_ problem of securely transferring the + identity of the caller to a remote site is not addressed. For + example, the problem of delegating credentials from the + `rlogin' client to the other machine without typing the + password is not addressed by our work. We also do not address + the problem of sending the passwords over the network in the + clear. + + (c) We do not address the source of information obtained from the + "`getXbyY()'" family of calls (e.g., `getpwnam()'). Different + operating systems address this problem differently. For + example, Solaris uses the name service switch (NSS) to + determine the source of information for the "`getXbyY()'" + calls. It is expected that data which is stored in multiple + sources (such as passwd entries in NIS+ and the DCE registry) + is kept in sync using the appropriate commands (such as + `passwd_export'). + + + + + + + + Samar, Schemers Page 4 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + 4. OVERVIEW OF THE PAM FRAMEWORK + + We propose that the goals listed above can be met through a framework + in which authentication modules can be _plugged_ independently of the + application. We call this the _Pluggable Authentication Modules_ + (PAM) framework. + + The core components of the PAM framework are the authentication + library API (the front end) and the authentication mechanism-specific + modules (the back end), connected through the Service Provider + Interface (SPI). Applications write to the PAM API, while the + authentication-system providers write to the PAM SPI and supply the + back end modules that are independent of the application. + + ftp telnet login (Applications) + | | | + | | | + +--------+--------+ + | + +-----+-----+ + | PAM API | <-- pam.conf file + +-----+-----+ + | + +--------+--------+ + UNIX Kerberos Smart Cards (Mechanisms) + + Figure 1: The Basic PAM Architecture + + Figure 1 illustrates the relationship between the application, the + PAM library, and the authentication modules. Three applications + (`login', `telnet' and `ftp') are shown which use the PAM + authentication interfaces. When an application makes a call to the + PAM API, it loads the appropriate authentication module as determined + by the configuration file, `pam.conf'. The request is forwarded to + the underlying authentication module (for example, UNIX password, + Kerberos, smart cards) to perform the specified operation. The PAM + layer then returns the response from the authentication module to the + application. + + PAM unifies system authentication and access control for the system, + and allows plugging of associated authentication modules through well + defined interfaces. The plugging can be defined through various + means, one of which uses a configuration file, such as the one in + Table 1. For each of the system applications, the file specifies the + authentication module that should be loaded. In the example below, + `login' uses the UNIX password module, while `ftp' and `telnet' use + the S/Key module. + + + + + + + + Samar, Schemers Page 5 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + Table 1: A Simplified View of a Sample PAM Configuration File. + + service module_path + ------- ----------- + login pam_unix.so + ftp pam_skey.so + telnet pam_skey.so + + Authentication configuration is only one aspect of this interface. + Other critical components include account management, session + management, and password management. For example, the `login' + program may want to verify not only the password but also whether the + account has aged or expired. Generic interfaces also need to be + provided so that the password can be changed according to the + requirements of the module. Furthermore, the application may want to + log information about the current session as determined by the + module. + + Not all applications or services may need all of the above + components, and not each authentication module may need to provide + support for all of the interfaces. For example, while `login' may + need access to all four components, `su' may need access to just the + authentication component. Some applications may use some specific + authentication and password management modules but share the account + and session management modules with others. + + This reasoning leads to a partitioning of the entire set of + interfaces into four areas of functionality: (1) authentication, (2) + account, (3) session, and (4) password. The concept of PAM was + extended to these functional areas by implementing each of them as a + separate pluggable module. + + Breaking the functionality into four modules helps the module + providers because they can use the system-provided libraries for the + modules that they are not changing. For example, if a supplier wants + to provide a better version of Kerberos, they can just provide that + new authentication and password module, and reuse the existing ones + for account and session. + + 4.1. Module Description + + More details on specific API's are described in Appendix A. A brief + description of four modules follows: + + (a) Authentication management: This set includes the + `pam_authenticate()' function to authenticate the user, and the + `pam_setcred()' interface to set, refresh or destroy the user + credentials. + + (b) Account management: This set includes the `pam_acct_mgmt()' + function to check whether the authenticated user should be + + + + Samar, Schemers Page 6 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + given access to his/her account. This function can implement + account expiration and access hour restrictions. + + (c) Session management: This set includes the `pam_open_session()' + and `pam_close_session()' functions for session management and + accounting. For example, the system may want to store the + total time for the session. + + (d) Password management: This set includes a function, + `pam_chauthtok()', to change the password. + + + 5. FRAMEWORK INTERFACES + + The PAM framework further provides a set of administrative interfaces + to support the above modules and to provide for application-module + communication. There is no corresponding service provider interface + (SPI) for such functions. + + 5.1. Administrative Interfaces + + Each set of PAM transactions starts with `pam_start()' and ends with + the `pam_end()' function. The interfaces `pam_get_item()' and + `pam_set_item()' are used to read and write the state information + associated with the PAM transaction. + + If there is any error with any of the PAM interfaces, the error + message can be printed with `pam_strerror()'. + + 5.2. Application-Module Communication + + During application initialization, certain data such as the user name + is saved in the PAM framework layer through `pam_start()' so that it + can be used by the underlying modules. The application can also pass + opaque data to the module which the modules will pass back while + communicating with the user. + + 5.3. User-Module Communication + + The `pam_start()' function also passes conversation function that has + to be used by the underlying modules to read and write module + specific authentication information. For example, these functions + can be used to prompt the user for the password in a way determined + by the application. PAM can thus be used by graphical, non- + graphical, or networked applications. + + + + + + + + + + Samar, Schemers Page 7 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + 5.4. Inter-Module Communication + + Though the modules are independent, they can share certain common + information about the authentication session such as user name, + service name, password, and conversation function through the + `pam_get_item()' and `pam_set_item()' interfaces. These API's can + also be used by the application to change the state information after + having called `pam_start()' once. + + 5.5. Module State Information + + The PAM service modules may want to keep certain module-specific + state information about the session. The interfaces `pam_get_data()' + and `pam_set_data()' can be used by the service modules to access and + update module-specific information as needed from the PAM handle. + The modules can also attach a cleanup function with the data. The + cleanup function is executed when `pam_end()' is called to indicate + the end of the current authentication activity. + + Since the PAM modules are loaded upon demand, there is no direct + module initialization support in the PAM framework. If there are + certain initialization tasks that the PAM service modules have to do, + they should be done upon the first invocation. However, if there are + certain clean-up tasks to be done when the authentication session + ends, the modules should use `pam_set_data()' to specify the clean-up + functions, which would be called when `pam_end()' is called by the + application. + + + 6. MODULE CONFIGURATION MANAGEMENT + + Table 2 shows an example of a configuration file `pam.conf' with + support for authentication, session, account, and password management + modules. `login' has three entries: one each for authentication + processing, session management and account management. Each entry + specifies the module name that should be loaded for the given module + type. In this example, the `ftp' service uses the authentication and + session modules. Note that all services here share the same session + management module, while having different authentication modules. + + + + + + + + + + + + + + + + Samar, Schemers Page 8 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + Table 2: Configuration File (pam.conf) with Different Modules + and Control Flow + + service module_type control_flag module_path options + ------- ----------- ------------ ----------- ------- + login auth required pam_unix_auth.so nowarn + login session required pam_unix_session.so + login account required pam_unix_account.so + ftp auth required pam_skey_auth.so debug + ftp session required pam_unix_session.so + telnet session required pam_unix_session.so + login password required pam_unix_passwd.so + passwd password required pam_unix_passwd.so + OTHER auth required pam_unix_auth.so + OTHER session required pam_unix_session.so + OTHER account required pam_unix_account.so + + The first field, _service_, denotes the service (for example, + `login', `passwd', `rlogin'). The name `OTHER' indicates the module + used by all other applications that have not been specified in this + file. This name can also be used if all services have the same + requirements. In the example, since all the services use the same + session module, we could have replaced those lines with a single + `OTHER' line. + + The second field, _module_type_, indicates the type of the PAM + functional module. It can be one of `auth', `account', `session', or + `password' modules. + + The third field, _control_flag_ determines the behavior of stacking + multiple modules by specifying whether any particular module is + _required_, _sufficient_, or _optional_. The next section describes + stacking in more detail. + + The fourth field, _module_path_, specifies the location of the + module. The PAM framework loads this module upon demand to invoke + the required function. + + The fifth field, _options_, is used by the PAM framework layer to + pass module specific options to the modules. It is up to the module + to parse and interpret the options. This field can be used by the + modules to turn on debugging or to pass any module specific + parameters such as a timeout value. It is also used to support + unified login as described below. The options field can be used by + the system administrator to fine-tune the PAM modules. + + If any of the fields are invalid, or if a module is not found, that + line is ignored and the error is logged as a critical error via + `syslog(3)'. If no entries are found for the given module type, then + the PAM framework returns an error to the application. + + + + + Samar, Schemers Page 9 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + 7. INTEGRATING MULTIPLE AUTHENTICATION SERVICES WITH STACKING + + In the world of heterogeneous systems, the system administrator often + has to deal with the problem of integrating multiple authentication + mechanisms. The user is often required to know about the + authentication command of the new authentication module (for example, + `kinit', `dce_login') after logging into the system. This is not + user-friendly because it forces people to remember to type the new + command and enter the new password. This functionality should be + invisible instead of burdening the user with it. + + There are two problems to be addressed here: + + (a) Supporting multiple authentication mechanisms. + + (b) Providing unified login in the presence of multiple mechanisms. + + In the previous section, we described how one could replace the + default authentication module with any other module of choice. Now + we demonstrate how the same model can be extended to provide support + for multiple modules. + + 7.1. Design for Stacked Modules + + One possibility was to provide hard-coded rules in `login' or other + applications requiring authentication services [Adamson 95]. But + this becomes very specific to the particular combination of + authentication protocols, and also requires the source code of the + application. Digital's Security Integration Architecture [SIA 95] + addresses this problem by specifying the same list of authentication + modules for all applications. Since requirements for various + applications can vary, it is essential that the configuration be on a + per-application basis. + + To support multiple authentication mechanisms, the PAM framework was + extended to support _stacking_. When any API is called, the back + ends for the stacked modules are invoked in the order listed, and the + result returned to the caller. In Figure 2, the authentication + service of `login' is stacked and the user is authenticated by UNIX, + Kerberos, and RSA authentication mechanisms. Note that in this + example, there is no stacking for session or account management + modules. + + + + + + + + + + + + + Samar, Schemers Page 10 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + login + | + +--------+--------+ + | | | + session auth account + | | | + +--+--+ +--+--+ +--+--+ + | PAM | | PAM | | PAM | + +--+--+ +--+--+ +--+--+ + | | | + UNIX UNIX UNIX + session auth account + | + Kerberos + auth + | + RSA + auth + + Figure 2: Stacking With the PAM Architecture + + Stacking is specified through additional entries in the configuration + file shown earlier. As shown in Table 2, for each application (such + as `login') the configuration file can specify multiple mechanisms + that have to be invoked in the specified order. When mechanisms + fail, the _control_flag_ decides which error should be returned to + the application. Since the user should not know which authentication + module failed when a bad password was typed, the PAM framework + continues to call other authentication modules on the stack even on + failure. The semantics of the control flag are as follows: + + (a) `required': With this flag, the module failure results in the + PAM framework returning the error to the caller _after_ + executing all other modules on the stack. For the function to + be able to return success to the application all `required' + modules have to report success. This flag is normally set when + authentication by this module is a _must_. + + (b) `optional': With this flag, the PAM framework ignores the + module failure and continues with the processing of the next + module in sequence. This flag is used when the user is allowed + to login even if that particular module has failed. + + (c) `sufficient': With this flag, if the module succeeds the PAM + framework returns success to the application immediately + without trying any other modules. For failure cases, the + _sufficient_ modules are treated as `optional'. + + Table 3 shows a sample configuration file that stacks the `login' + command. Here the user is authenticated by UNIX, Kerberos, and RSA + authentication services. The `required' key word for _control_flag_ + + + + Samar, Schemers Page 11 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + enforces that the user is allowed to login only if he/she is + authenticated by _both_ UNIX and Kerberos services. RSA + authentication is optional by virtue of the `optional' key word in + the _control_flag_ field. The user can still log in even if RSA + authentication fails. + + Table 3: PAM Configuration File with Support for Stacking + + service module_type control_flag module_path options + ------- ----------- ------------ ----------- ------- + login auth required pam_unix.so debug + login auth required pam_kerb.so use_mapped_pass + login auth optional pam_rsa.so use_first_pass + + Table 4 illustrates the use of the sufficient flag for the `rlogin' + service. The Berkeley `rlogin' protocol specifies that if the remote + host is trusted (as specified in the `/etc/hosts.equiv' file or in + the `.rhosts' file in the home directory of the user), then the + `rlogin' daemon should not require the user to type the password. If + this is not the case, then the user is required to type the password. + Instead of hard coding this policy in the `rlogin' daemon, this can + be expressed with the `pam.conf' file in Table 4. The PAM module + `pam_rhosts_auth.so.1' implements the `.rhosts' policy described + above. If a site administrator wants to enable remote login with + only passwords, then the first line should be deleted. + + Table 4: PAM Configuration File for the rlogin service + + service module_type control_flag module_path options + ------- ----------- ------------ ----------- ------- + rlogin auth sufficient pam_rhosts_auth.so + rlogin auth required pam_unix.so + + 7.2. Password-Mapping + + Multiple authentication mechanisms on a machine can lead to multiple + passwords that users have to remember. One attractive solution from + the ease-of-use viewpoint is to use the same password for all + mechanisms. This, however, can also weaken the security because if + that password were to be compromised in any of the multiple + mechanisms, all mechanisms would be compromised at the same time. + Furthermore, different authentication mechanisms may have their own + distinctive password requirements in regards to its length, allowed + characters, time interval between updates, aging, locking, and so + forth. These requirements make it problematic to use the same + password for multiple authentication mechanisms. + + The solution we propose, while not precluding use of the same + password for every mechanism, allows for a different password for + each mechanism through what we call _password-mapping_. This + basically means using the user's _primary_ password to encrypt the + + + + Samar, Schemers Page 12 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + user's other (_secondary_) passwords, and storing these encrypted + passwords in a place where they are available to the user. Once the + primary password is verified, the authentication modules would obtain + the other passwords for their own mechanisms by decrypting the + mechanism-specific encrypted password with the primary password, and + passing it to the authentication service. The security of this + design for password-mapping assumes that the primary password is the + user's strongest password, in terms of its unguessability (length, + type and mix of characters used, etc.). + + If there is any error in password-mapping, or if the mapping does not + exist, the user will be prompted for the password by each + authentication module. + + To support password-mapping, the PAM framework saves the primary + password and provides it to stacked authentication modules. The + password is cleared out before the `pam_authenticate' function + returns. + + How the password is encrypted depends completely on the module + implementation. The encrypted secondary password (also called a + "mapped password") can be stored in a trusted or untrusted place, + such as a smart card, a local file, or a directory service. If the + encrypted passwords are stored in an untrusted publicly accessible + place, this does provide an intruder with opportunities for potential + dictionary attack. + + Though password-mapping is voluntary, it is recommended that all + module providers add support for the following four mapping options: + + (a) `use_first_pass': Use the same password used by the first + mechanism that asked for a password. The module should not ask + for the password if the user cannot be authenticated by the + first password. This option is normally used when the system + administrator wants to enforce the same password across + multiple modules. + + (b) `try_first_pass': This is the same as `use_first_pass', except + that if the primary password is not valid, it should prompt the + user for the password. + + (c) `use_mapped_pass': Use the password-mapping scheme to get the + actual password for this module. One possible implementation + is to get the mapped-password using the XFN API [XFN 94], and + decrypt it with the primary password to get the module-specific + password. The module should not ask for the password if the + user cannot be authenticated by the first password. The XFN + API allows user-defined attributes (such as _mapped-password_) + to be stored in the _user-context_. Using the XFN API is + particularly attractive because support for the XFN may be + found on many systems in the future. + + + + Samar, Schemers Page 13 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + (d) `try_mapped_pass': This is the same as `use_mapped_pass', + except that if the primary password is not valid, it should + prompt the user for the password. + + When passwords get updated, the PAM framework stores both the old as + well as the new password to be able to inform other dependent + authentication modules about the change. Other modules can use this + information to update the encrypted password without forcing the user + to type the sequence of passwords again. The PAM framework clears + out the passwords before returning to the application. + + Table 3 illustrates how the same password can be used by `login' for + authenticating to the standard UNIX login, Kerberos and RSA services. + Once the user has been authenticated to the primary authentication + service (UNIX `login' in this example) with the primary password, the + option `use_mapped_pass' indicates to the Kerberos module that it + should use the primary password to decrypt the stored Kerberos + password and then use the Kerberos password to get the ticket for the + ticket-granting-service. After that succeeds, the option + `use_first_pass' indicates to the RSA module that instead of + prompting the user for a password, it should use the primary password + typed earlier for authenticating the user. Note that in this + scenario, the user has to enter the password just once. + + Note that if a one-time password scheme (e.g., S/Key) is used, + password mapping cannot apply. + + 7.3. Implications of Stacking on the PAM Design + + Because of the stacking capability of PAM, we have designed the PAM + API's to not return any data to the application, except status. If + this were not the case, it would be difficult for the PAM framework + to decide which module should return data to the application. When + there is any error, the application does not know which of the + modules failed. This behavior enables (even requires) the + application to be completely independent from the modules. + + Another design decision we have made is that PAM gives only the user + name to all the underlying PAM modules, hence it is the + responsibility of the PAM modules to convert the name to their own + internal format. For example, the Kerberos module may have to + convert the UNIX user name to a Kerberos principal name. + + Stacking also forces the modules to be designed such that they can + occur anywhere in the stack without any side-effects. + + Since modules such as the authentication and the password module are + very closely related, it is important they be configured in the same + order and with compatible options. + + + + + + Samar, Schemers Page 14 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + 8. INTEGRATION WITH SMART CARDS + + Many networking authentication protocols require possession of a long + key to establish the user identity. For ease-of-use reasons, that + long key is normally encrypted with the user's password so that the + user is not required to memorize it. However, weak passwords can be + compromised through a dictionary attack and thus undermine the + stronger network authentication mechanism. Furthermore, the + encrypted data is normally stored in a centrally accessible service + whose availability depends upon the reliability of the associated + service. Solutions have been proposed to use a pass-phrase or one- + time-password, but those are much longer than the regular eight + character passwords traditionally used with UNIX `login'. This makes + the solution user-unfriendly because it requires longer strings to be + remembered and typed. + + For most authentication protocol implementations, the trust boundary + is the local machine. This assumption may not be valid in cases + where the user is mobile and has to use publicly available networked + computers. In such cases, it is required that the clear text of the + key or the password never be made available to the machine. + + Smart cards solve the above problems by reducing password exposure by + supporting a _two factor_ authentication mechanism: the first with + the possession of the card, and the second with the knowledge of the + PIN associated with the card. Not only can the smart cards be a + secure repository of multiple passwords, they can also provide the + encryption and authentication functions such that the long (private) + key is never exposed outside the card. + + The PAM framework allows for integrating smart cards to the system by + providing a smart card specific module for authentication. + Furthermore, the unified login problem is simplified because the + multiple passwords for various authentication mechanisms can be + stored on the smart card itself. This can be enabled by adding a + suitable key-word such as `use_smart_card' in the _options_ field. + + + 9. SECURITY ISSUES + + It is important to understand the impact of PAM on the security of + any system so that the site-administrator can make an informed + decision. + + (a) Sharing of passwords with multiple authentication mechanisms. + + If there are multiple authentication modules, one possibility + is to use the same password for all of them. If the password + for any of the multiple authentication system is compromised, + the user's password in all systems would be compromised. If + this is a concern, then multiple passwords might be considered + + + + Samar, Schemers Page 15 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + at the cost of ease-of-use. + + (b) Password-mapping. + + This technique of encrypting all other passwords with the + primary password assumes that it is lot more difficult to crack + the primary password and that reasonable steps have been taken + to ensure limited availability of the encrypted primary + password. If this is not done, an intruder could target the + primary password as the first point of dictionary attack. If + one of the other modules provide stronger security than the + password based security, the site would be negating the strong + security by using password-mapping. If this is a concern, then + multiple passwords might be considered at the cost of ease-of- + use. If smart cards are used, they obviate the need for + password-mapping completely. + + (c) Security of the configuration file. + + Since the policy file dictates how the user is authenticated, + this file should be protected from unauthorized modifications. + + (d) Stacking various PAM modules. + + The system administrator should fully understand the + implications of stacking various modules that will be installed + on the system and their respective orders and interactions. + The composition of various authentication modules should be + carefully examined. The trusted computing base of the machine + now includes the PAM modules. + + + 10. EXPERIENCE WITH PAM + + The PAM framework was first added in Solaris 2.3 release as a private + internal interface. PAM is currently being used by several system + entry applications such as `login', `passwd', `su', `dtlogin', + `rlogind', `rshd', `telnetd', `ftpd', `in.rexecd', `uucpd', `init', + `sac', and `ttymon'. We have found that PAM provides an excellent + framework to encapsulate the authentication-related tasks for the + entire system. The Solaris 2.3 PAM API's were hence enhanced and + simplified to support stacking. + + PAM modules have been developed for UNIX, DCE, Kerberos, S/Key, + remote user authentication, and dialpass authentication. Other PAM + modules are under development, and integration with smart cards is + being planned. + + Some third parties have used the PAM interface to extend the security + mechanisms offered by the Solaris environment. + + + + + Samar, Schemers Page 16 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + The PAM API has been accepted by Common Desktop Environment (CDE) + vendors as the API to be used for integrating the graphical interface + for login, `dtlogin' with multiple authentication mechanisms. + + + 11. FUTURE WORK + + Amongst the various components of PAM, the password component needs + to be carefully examined to see whether the stacking semantics are + particularly applicable, and how PAM should deal with partial + failures when changing passwords. + + The _control_flag_ of the configuration file can be extended to + include other semantics. For example, if the error is "name service + not available", one may want to retry. It is also possible to offer + semantics of "return success if any of the modules return success". + + In an earlier section, we had mentioned integration of smart cards + with PAM. Though we feel that integration should be straight forward + from the PAM architecture point of view, there may be some issues + with implementation because the interfaces to the smart cards have + not yet been standardized. + + One possible extension to PAM is to allow the passing of module- + specific data between applications and PAM modules. For example, the + `login' program likes to build its new environment from a select list + of variables, yet the DCE module needs the `KRB5CCNAME' variable to + be exported to the child process. For now we have modified the + `login' program to explicitly export the `KRB5CCNAME' variable. + + Administrative tools are needed to help system administrators modify + `pam.conf', and perform sanity checks on it (i.e., a `pam_check' + utility). + + + 12. CONCLUSION + + The PAM framework and the module interfaces provide pluggability for + user authentication, as well as for account, session and password + management. The PAM architecture can be used by `login' and by all + other system-entry services, and thus ensure that all entry points + for the system have been secured. This architecture enables + replacement and modification of authentication modules in the field + to secure the system against the newly found weaknesses without + changing any of the system services. + + The PAM framework can be used to integrate `login' and `dtlogin' with + different authentication mechanisms such as RSA and Kerberos. + Multiple authentication systems can be accessed with the same + password. The PAM framework also provides easy integration of smart + cards into the system. + + + + Samar, Schemers Page 17 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + PAM provides complementary functionality to GSS-API, in that it + provides mechanisms through which the user gets authenticated to any + new system-level authentication service on the machine. GSS-API then + uses the credentials for authenticated and secure communications with + other application-level service entities on the network. + + + 13. ACKNOWLEDGEMENTS + + PAM development has spanned several release cycles at SunSoft. + Shau-Ping Lo, Chuck Hickey, and Alex Choy did the first design and + implementation. Bill Shannon and Don Stephenson helped with the PAM + architecture. Rocky Wu prototyped stacking of multiple modules. + Paul Fronberg, Charlie Lai, and Roland Schemers made very significant + enhancements to the PAM interfaces and took the project to completion + within a very short time. Kathy Slattery wrote the PAM + documentation. John Perry integrated PAM within the CDE framework. + + + APPENDIX A. PAM API'S + + This appendix gives an informal description of the various interfaces + of PAM. Since the goal here is just for the reader to get a working + knowledge about the PAM interfaces, not all flags and options have + been fully defined and explained. The API's described here are + subject to change. + + The PAM Service Provider Interface is very similar to the PAM API, + except for one extra parameter to pass module-specific options to the + underlying modules. + + A.1. Framework Layer API's + + int + pam_start( + char *service_name, + char *user, + struct pam_conv *pam_conversation, + pam_handle_t **pamh + ); + + `pam_start()' is called to initiate an authentication transaction. + `pam_start()' takes as arguments the name of the service, the name of + the user to be authenticated, the address of the conversation + structure. `pamh' is later used as a handle for subsequent calls to + the PAM library. + + The PAM modules do not communicate directly with the user; instead + they rely on the application to perform all such interaction. The + application needs to provide the conversation functions, `conv()', + and associated application data pointers through a `pam_conv' + + + + Samar, Schemers Page 18 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + structure when it initiates an authentication transaction. The + module uses the `conv()' function to prompt the user for data, + display error messages, or text information. + + int + pam_end( + pam_handle_t *pamh, + int pam_status + ); + + `pam_end()' is called to terminate the PAM transaction as specified + by `pamh', and to free any storage area allocated by the PAM modules + with `pam_set_item()'. + + int + pam_set_item( + pam_handle_t *pamh, + int item_type, + void *item + ); + + int + pam_get_item( + pam_handle_t *pamh, + int item_type, + void **item); + + `pam_get_item()' and `pam_set_item()' allow the parameters specified + in the initial call to `pam_start()' to be read and updated. This is + useful when a particular parameter is not available when + `pam_start()' is called or must be modified after the initial call to + `pam_start()'. `pam_set_item()' is passed a pointer to the object, + `item', and its type, `item_type'. `pam_get_item()' is passed the + address of the pointer, `item', which is assigned the address of the + requested object. + + The `item_type' is one of the following: + + Table 5: Possible Values for Item_type + + Item Name Description + --------- ----------- + PAM_SERVICE The service name + PAM_USER The user name + PAM_TTY The tty name + PAM_RHOST The remote host name + PAM_CONV The pam_conv structure + PAM_AUTHTOK The authentication token (password) + PAM_OLDAUTHTOK The old authentication token + PAM_RUSER The remote user name + + + + + Samar, Schemers Page 19 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + Note that the values of `PAM_AUTHTOK' and `PAM_OLDAUTHTOK' are only + available to PAM modules and not to the applications. They are + explicitly cleared out by the framework before returning to the + application. + + char * + pam_strerror( + int errnum + ); + + `pam_strerror()' maps the error number to a PAM error message string, + and returns a pointer to that string. + + int + pam_set_data( + pam_handle_t *pamh, + char *module_data_name, + char *data, + (*cleanup)(pam_handle_t *pamh, char *data, + int error_status) + ); + + The `pam_set_data()' function stores module specific data within the + PAM handle. The `module_data_name' uniquely specifies the name to + which some data and cleanup callback function can be attached. The + cleanup function is called when `pam_end()' is invoked. + + int + pam_get_data( + pam_handle_t *pamh, + char *module_data_name, + void **datap + ); + + The `pam_get_data()' function obtains module-specific data from the + PAM handle stored previously by the `pam_get_data()' function. The + `module_data_name' uniquely specifies the name for which data has to + be obtained. This function is normally used to retrieve module + specific state information. + + A.2. Authentication API's + + int + pam_authenticate( + pam_handle_t *pamh, + int flags + ); + + The `pam_authenticate()' function is called to verify the identity of + the current user. The user is usually required to enter a password + or similar authentication token, depending upon the authentication + + + + Samar, Schemers Page 20 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + module configured with the system. The user in question is specified + by a prior call to `pam_start()', and is referenced by the + authentication handle, `pamh'. + + int + pam_setcred( + pam_handle_t *pamh, + int flags + ); + + The `pam_setcred()' function is called to set the credentials of the + current process associated with the authentication handle, `pamh'. + The actions that can be denoted through `flags' include credential + initialization, refresh, reinitialization and deletion. + + A.3. Account Management API + + int + pam_acct_mgmt( + pam_handle_t *pamh, + int flags + ); + + The function `pam_acct_mgmt()' is called to determine whether the + current user's account and password are valid. This typically + includes checking for password and account expiration, valid login + times, etc. The user in question is specified by a prior call to + `pam_start()', and is referenced by the authentication handle, + `pamh'. + + A.4. Session Management API's + + int + pam_open_session( + pam_handle_t *pamh, + int flags + ); + + `pam_open_session()' is called to inform the session modules that a + new session has been initialized. All programs which use PAM should + invoke `pam_open_session()' when beginning a new session. + + int + pam_close_session( + pam_handle_t *pamh, + int flags + ); + + Upon termination of this session, the `pam_close_session()' function + should be invoked to inform the underlying modules that the session + has terminated. + + + + Samar, Schemers Page 21 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + A.5. Password Management API's + + int + pam_chauthtok( + pam_handle_t *pamh, + int flags + ); + + `pam_chauthtok()' is called to change the authentication token + associated with the user referenced by the authentication handle + `pamh'. After the call, the authentication token of the user will be + changed in accordance with the authentication module configured on + the system. + + + APPENDIX B. SAMPLE PAM APPLICATION + + This appendix shows a sample `login' application which uses the PAM + API's. It is not meant to be a fully functional login program, as + some functionality has been left out in order to emphasize the use of + PAM API's. + + #include <security/pam_appl.h> + + static int login_conv(int num_msg, struct pam_message **msg, + struct pam_response **response, void *appdata_ptr); + + static struct pam_conv pam_conv = {login_conv, NULL}; + + static pam_handle_t *pamh; /* Authentication handle */ + + void + main(int argc, char *argv[], char **renvp) + { + + /* + * Call pam_start to initiate a PAM authentication operation + */ + + if ((pam_start("login", user_name, &pam_conv, &pamh)) + != PAM_SUCCESS) + login_exit(1); + + pam_set_item(pamh, PAM_TTY, ttyn); + pam_set_item(pamh, PAM_RHOST, remote_host); + + while (!authenticated && retry < MAX_RETRIES) { + status = pam_authenticate(pamh, 0); + authenticated = (status == PAM_SUCCESS); + } + + + + + Samar, Schemers Page 22 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + if (status != PAM_SUCCESS) { + fprintf(stderr,"error: %s\n", pam_strerror(status)); + login_exit(1); + } + + /* now check if the authenticated user is allowed to login. */ + + if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { + if (status == PAM_AUTHTOK_EXPIRED) { + status = pam_chauthtok(pamh, 0); + if (status != PAM_SUCCESS) + login_exit(1); + } else { + login_exit(1); + } + } + + /* + * call pam_open_session to open the authenticated session + * pam_close_session gets called by the process that + * cleans up the utmp entry (i.e., init) + */ + if (status = pam_open_session(pamh, 0) != PAM_SUCCESS) { + login_exit(status); + } + + /* set up the process credentials */ + setgid(pwd->pw_gid); + + /* + * Initialize the supplementary group access list. + * This should be done before pam_setcred because + * the PAM modules might add groups during the pam_setcred call + */ + initgroups(user_name, pwd->pw_gid); + + status = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (status != PAM_SUCCESS) { + login_exit(status); + } + + /* set the real (and effective) UID */ + setuid(pwd->pw_uid); + + pam_end(pamh, PAM_SUCCESS); /* Done using PAM */ + + /* + * Add DCE/Kerberos cred name, if any. + * XXX - The module specific stuff should be removed from login + * program eventually. This is better placed in DCE module and + * will be once PAM has routines for "exporting" environment + + + + Samar, Schemers Page 23 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + * variables. + */ + krb5p = getenv("KRB5CCNAME"); + if (krb5p != NULL) { + ENVSTRNCAT(krb5ccname, krb5p); + envinit[basicenv++] = krb5ccname; + } + environ = envinit; /* Switch to the new environment. */ + exec_the_shell(); + + /* All done */ + } + + /* + * login_exit - Call exit() and terminate. + * This function is here for PAM so cleanup can + * be done before the process exits. + */ + static void + login_exit(int exit_code) + { + if (pamh) + pam_end(pamh, PAM_ABORT); + exit(exit_code); + /*NOTREACHED*/ + } + + /* + * login_conv(): + * This is the conv (conversation) function called from + * a PAM authentication module to print error messages + * or garner information from the user. + */ + + static int + login_conv(int num_msg, struct pam_message **msg, + struct pam_response **response, void *appdata_ptr) + { + + while (num_msg--) { + switch (m->msg_style) { + + case PAM_PROMPT_ECHO_OFF: + r->resp = strdup(getpass(m->msg)); + break; + + case PAM_PROMPT_ECHO_ON: + (void) fputs(m->msg, stdout); + r->resp = malloc(PAM_MAX_RESP_SIZE); + fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); + /* add code here to remove \n from fputs */ + + + + Samar, Schemers Page 24 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + break; + + case PAM_ERROR_MSG: + (void) fputs(m->msg, stderr); + break; + + case PAM_TEXT_INFO: + (void) fputs(m->msg, stdout); + break; + + default: + /* add code here to log error message, etc */ + break; + } + } + return (PAM_SUCCESS); + } + + + APPENDIX C. DCE MODULE + + This appendix describes a sample implementation of a DCE PAM module. + In order to simplify the description, we do not address the issues + raised by password-mapping or stacking. The intent is to show which + DCE calls are being made by the DCE module. + + The `pam_sm_*()' functions implement the PAM SPI functions which are + called from the PAM API functions. + + C.1. DCE Authentication Management + + The algorithm for authenticating with DCE (not including error + checking, prompting for passwords, etc.) is as follows: + + pam_sm_authenticate() + { + sec_login_setup_identity(...); + pam_set_data(...); + sec_login_valid_and_cert_ident(...); + } + + pam_sm_setcred() + { + pam_get_data(...); + sec_login_set_context(...); + } + + The `pam_sm_authenticate()' function for DCE uses the + `pam_set_data()' and `pam_get_data()' functions to keep state (like + the `sec_login_handle_t' context) between calls. The following + cleanup function is also registered and gets called when `pam_end()' + + + + Samar, Schemers Page 25 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + is called: + + dce_cleanup() + { + if (/* PAM_SUCCESS and + sec_login_valid_and_cert_ident success */) { + sec_login_release_context(...); + } else { + sec_login_purge_context(...); + } + } + + If everything was successful we release the login context, but leave + the credentials file intact. If the status passed to `pam_end()' was + not `PAM_SUCCESS' (i.e., a required module failed) we purge the login + context which also removes the credentials file. + + C.2. DCE Account Management + + The algorithm for DCE account management is as follows: + + pam_sm_acct_mgmt() + { + pam_get_data(...); + sec_login_inquire_net_info(...); + /* check for expired password and account */ + sec_login_free_net_info(...); + } + + The `sec_login_inquire_net_info()' function is called to obtain + information about when the user's account and/or password are going + to expire. A warning message is displayed (using the conversation + function) if the user's account or password is going to expire in the + near future, or has expired. These warning messages can be disabled + using the `nowarn' option in the `pam.conf' file. + + C.3. DCE Session Management + + The DCE session management functions are currently empty. They could + be modified to optionally remove the DCE credentials file upon + logout, etc. + + C.4. DCE Password Management + + The algorithm for DCE password management is as follows: + + + + + + + + + + Samar, Schemers Page 26 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + pam_sm_chauthtok + { + sec_rgy_site_open(...); + sec_rgy_acct_lookup(...); + sec_rgy_acct_passwd(...); + sec_rgy_site_close(...); + } + + The `sec_rgy_acct_passwd()' function is called to change the user's + password in the DCE registry. + + + REFERENCES + + [Adamson 95] W. A. Adamson, J. Rees, and P. Honeyman, "Joining + Security Realms: A Single Login for Netware and + Kerberos", CITI Technical Report 95-1, Center for + Information Technology Integration, University of + Michigan, Ann Arbor, MI, February 1995. + + [Diffie 76] W. Diffie and M. E. Hellman, "New Directions in + Cryptography", IEEE Transactions on Information + Theory, November 1976. + + [Linn 93] J. Linn, "Generic Security Service Application + Programming Interface", Internet RFC 1508, 1509, 1993. + + [Rivest 78] R. L. Rivest, A. Shamir, and L. Adleman., "A Method + for Obtaining Digital Signatures and Pubic-key + Cryptosystems", Communications of the ACM, 21(2), + 1978. + + [SIA 95] "Digital UNIX Security", Digital Equipment + Corporation, Order Number AA-Q0R2C-TE, July 1995. + + [Skey 94] N. M. Haller, "The S/Key One-Time Password System", + ISOC Symposium on Network and Distributed Security, + 1994. + + [Steiner 88] J.G. Steiner, B. C. Neuman, and J. I. Schiller, + "Kerberos, An Authentication Service for Open Network + Systems", in Proceedings of the Winter USENIX + Conference, Dallas, Jan 1988. + + [Taylor 88] B. Taylor and D. Goldberg, "Secure Networking in the + Sun Environment", Sun Microsystems Technical Paper, + 1988. + + [XFN 94] "Federated Naming: the XFN Specifications", X/Open + Preliminary Specification, X/Open Document #P403, + ISBN:1-85912-045-8, X/Open Co. Ltd., July 1994. + + + + Samar, Schemers Page 27 + + + + + + + + OSF-RFC 86.0 PAM October 1995 + + + + AUTHOR'S ADDRESS + + Vipin Samar Internet email: vipin@eng.sun.com + SunSoft, Inc. Telephone: +1-415-336-1002 + 2550 Garcia Avenue + Mountain View, CA 94043 + USA + + Roland J. Schemers III Internet email: schemers@eng.sun.com + SunSoft, Inc. Telephone: +1-415-336-1035 + 2550 Garcia Avenue + Mountain View, CA 94043 + USA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Samar, Schemers Page 28 + + + + + + diff --git a/Linux-PAM/doc/specs/std-agent-id.raw b/Linux-PAM/doc/specs/std-agent-id.raw new file mode 100644 index 00000000..61d5bc4a --- /dev/null +++ b/Linux-PAM/doc/specs/std-agent-id.raw @@ -0,0 +1,95 @@ +PAM working group ## A.G. Morgan + +## $Id: std-agent-id.raw,v 1.1.1.1 2002/09/15 20:08:34 hartmans Exp $ ## + +## Pluggable Authentication Modules ## + +## REGISTERED AGENTS AND THEIR AGENT-ID'S ## + +#$ Purpose of this document + +#$$#{definition} Definition of an agent-id + +The most complete version of a "PAM agent-id" is contained in this +reference [#$R#{PAM_RFC2}]. A copy of a recent definition is +reproduced here for convenience. The reader is recommended to consult +reference [#{PAM_RFC2}] for definitions of other terms that are +used in this document. + +## -------------- ## + +The agent_id is a sequence of characters satisfying the following +regexp: + + /^[a-z0-9\_]+(@[a-z0-9\_.]+)?$/ + +and has a specific form for each independent agent. + +o Agent_ids that do not contain an at-sign (@) are to be considered as + representing some authentication mode that is a "public + standard". Registered names MUST NOT contain an at-sign (@). + +o Anyone can define additional agents by using names in the format + name@domainname, e.g. "ouragent@example.com". The part following + the at-sign MUST be a valid fully qualified internet domain name + [RFC-1034] controlled by the person or organization defining the + name. (Said another way, if you control the email address that + your agent has as an identifier, they you are entitled to use + this identifier.) It is up to each domain how it manages its local + namespace. + +## -------------- ## + +#$ Registered agent-id's + +The structure of this section is a single subsection for each +registered agent-id. This section includes a full definition of binary +prompts accepted by the agent and example responses of said +agent. Using the defining section alone, it should be possible for a +third party to create a conforming agent and modules that can +interoperate with other implementations of these objects. + +*$ "userpass" - the user+password agent + +Many legacy authentication systems are hardcoded to support one and +only one authentication method. Namely, + + username: joe + password: <secret> + +Indeed, this authentication method is often embedded into parts of the +transport protocol. The "user+password" agent with PAM agent-id: + + "userpass" + +Is intended to support this legacy authentication scheme. The protocol +for binary prompt exchange with this 'standard agent' is as follows: + +Case 1: module does not know the username, but expects the agent to + obtain this information and also the user's password: + + module: {LENGTH;PAM_BP_SELECT;userpass;'/'} + agent: {} + +Case 2: module has suggested username, but would like agent to confirm + it and gather password: + + module: {} + agent: {} + +Case 3: module knows username and will not permit the agent to change it: + + module: {} + agent: {} + +#$ References + +[#{PAM_RFC2}] Internet draft, "Pluggable Authentication Modules + (PAM)", available here: + +# http://linux.kernel.org/pub/linux/libs/pam/pre/doc/current-draft.txt # + +#$ Author's Address + +Andrew G. Morgan +Email: morgan@kernel.org diff --git a/Linux-PAM/doc/txts/README b/Linux-PAM/doc/txts/README new file mode 100644 index 00000000..785f59f8 --- /dev/null +++ b/Linux-PAM/doc/txts/README @@ -0,0 +1,3 @@ +$Id: README,v 1.1.1.1 2001/04/29 04:17:03 hartmans Exp $ + +This is a directory for text versions of the pam documentation diff --git a/Linux-PAM/dynamic/Makefile b/Linux-PAM/dynamic/Makefile new file mode 100644 index 00000000..72d5a08a --- /dev/null +++ b/Linux-PAM/dynamic/Makefile @@ -0,0 +1,70 @@ +# +# $Id: Makefile,v 1.1.1.1 2002/09/15 20:08:35 hartmans Exp $ +# +# + +include ../Make.Rules + +ifeq ($(WITH_LIBDEBUG),yes) + LIBNAME=pamd +else + LIBNAME=pam +endif +VERSION=.$(MAJOR_REL) +MODIFICATION=.$(MINOR_REL) + +# --------------------------------------------- + +dummy: ../Make.Rules all + +# --------------------------------------------- + +# dynamic library names + +PAMSHOBJ = pam.so +PAMSHOBJMAJ = $(PAMSHOBJ)$(VERSION) + +DLIBOBJECTS = pam.o + +# --------------------------------------------- +## rules + +all: dirs $(PAMSHOBJ) ../Make.Rules + +dirs: +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) dynamic +endif +ifeq ($(STATIC_LIBPAM),yes) + $(MKDIR) static +endif + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(PAMSHOBJ): $(DLIBOBJECTS) +ifeq ($(USESONAME),yes) + $(LD_L) $(SOSWITCH) $(PAMSHOBJMAJ) -o $@ $+ $(LINKLIBS) +else + $(LD_L) -o $@ $(DLIBOBJECTS) $(LINKLIBS) +endif + +install: all + $(MKDIR) $(FAKEROOT)$(libdir) +ifeq ($(DYNAMIC_LIBPAM),yes) + $(INSTALL) -m $(SHLIBMODE) $(PAMSHOBJ) $(FAKEROOT)$(libdir)/$(PAMSHOBJ) + $(LDCONFIG) +endif + +remove: + rm -f $(FAKEROOT)$(libdir)/$(LIBPAM) + $(LDCONFIG) + +clean: + rm -f a.out core *~ static/*.o dynamic/*.o + rm -f *.a *.o *.so ./include/security/*~ + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi diff --git a/Linux-PAM/dynamic/pam.c b/Linux-PAM/dynamic/pam.c new file mode 100644 index 00000000..c7b158d7 --- /dev/null +++ b/Linux-PAM/dynamic/pam.c @@ -0,0 +1,180 @@ +/* + * $Id: pam.c,v 1.1.1.1 2002/09/15 20:08:35 hartmans Exp $ + * + * If you want to dynamically load libpam using dlopen() or something, + * then dlopen( ' this shared object ' ); It takes care of exporting + * the right symbols to any modules loaded by libpam. + */ + +#include <stdio.h> +#include <dlfcn.h> +#include <security/pam_appl.h> +#include <security/_pam_macros.h> + +#ifndef LIBPAMPATH +#define LIBPAMPATH "/lib/libpam.so" +#endif + +static void *libpam_h = NULL; + +#define CONFIRM_PAM_FUNCTION(x, y, z, err) \ + do { \ + union { const void *tpointer; y (*fn) z ; } fptr; \ + fptr.tpointer = dlsym(libpam_h, #x); real_##x = fptr.fn; \ + if (real_##x == NULL) { \ + D(("unable to resolve '" #x "': %s", dlerror())); \ + return err; \ + } \ + } while (0) + + +extern void _init(void); + +void _init() +{ + if (libpam_h == NULL) { + libpam_h = dlopen(LIBPAMPATH, RTLD_GLOBAL|RTLD_NOW); + } +} + +extern void _fini(void); + +void _fini() +{ + if (libpam_h != NULL) { + dlclose(libpam_h); + } +} + +int pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh) +{ + static int (*real_pam_start)(const char *, const char *, + const struct pam_conv *, + pam_handle_t **); + CONFIRM_PAM_FUNCTION(pam_start, int, (const char *, const char *, + const struct pam_conv *, + pam_handle_t **), PAM_ABORT); + return real_pam_start(service_name, user, pam_conversation, pamh); +} + +int pam_end(pam_handle_t *pamh, int pam_status) +{ + static int (*real_pam_end)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_end, int, (pam_handle_t *, int), PAM_ABORT); + return real_pam_end(pamh, pam_status); +} + +int pam_set_item(pam_handle_t *pamh, int item_type, const void *item) +{ + static int (*real_pam_set_item)(pam_handle_t *, int, const void *); + CONFIRM_PAM_FUNCTION(pam_set_item, int, + (pam_handle_t *, int, const void *), PAM_ABORT); + return real_pam_set_item(pamh, item_type, item); +} + +int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) +{ + static int (*real_pam_get_item)(const pam_handle_t *, int, const void **); + CONFIRM_PAM_FUNCTION(pam_get_item, int, + (const pam_handle_t *, int, const void **), + PAM_ABORT); + return real_pam_get_item(pamh, item_type, item); +} + +int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay) +{ + static int (*real_pam_fail_delay)(pam_handle_t *, unsigned int); + CONFIRM_PAM_FUNCTION(pam_fail_delay, int, (pam_handle_t *, unsigned int), + PAM_ABORT); + return real_pam_fail_delay(pamh, musec_delay); +} + +typedef const char * const_char_pointer; + +const_char_pointer pam_strerror(pam_handle_t *pamh, int errnum) +{ + static const_char_pointer (*real_pam_strerror)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_strerror, const_char_pointer, + (pam_handle_t *, int), NULL); + return real_pam_strerror(pamh, errnum); +} + +int pam_putenv(pam_handle_t *pamh, const char *name_value) +{ + static int (*real_pam_putenv)(pam_handle_t *, const char *); + CONFIRM_PAM_FUNCTION(pam_putenv, int, (pam_handle_t *, const char *), + PAM_ABORT); + return real_pam_putenv(pamh, name_value); +} + +const_char_pointer pam_getenv(pam_handle_t *pamh, const char *name) +{ + static const_char_pointer (*real_pam_getenv)(pam_handle_t *, const char *); + CONFIRM_PAM_FUNCTION(pam_getenv, const_char_pointer, + (pam_handle_t *, const char *), NULL); + return real_pam_getenv(pamh, name); +} + +typedef char ** char_ppointer; +char_ppointer pam_getenvlist(pam_handle_t *pamh) +{ + static char_ppointer (*real_pam_getenvlist)(pam_handle_t *); + CONFIRM_PAM_FUNCTION(pam_getenvlist, char_ppointer, (pam_handle_t *), + NULL); + return real_pam_getenvlist(pamh); +} + +/* Authentication management */ + +int pam_authenticate(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_authenticate)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_authenticate, int, (pam_handle_t *, int), + PAM_ABORT); + return real_pam_authenticate(pamh, flags); +} + +int pam_setcred(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_setcred)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_setcred, int, (pam_handle_t *, int), PAM_ABORT); + return real_pam_setcred(pamh, flags); +} + +/* Account Management API's */ + +int pam_acct_mgmt(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_acct_mgmt)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_acct_mgmt, int, (pam_handle_t *, int), PAM_ABORT); + return real_pam_acct_mgmt(pamh, flags); +} + +/* Session Management API's */ + +int pam_open_session(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_open_session)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_open_session, int, (pam_handle_t *, int), + PAM_ABORT); + return real_pam_open_session(pamh, flags); +} + +int pam_close_session(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_close_session)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_close_session, int, (pam_handle_t *, int), + PAM_ABORT); + return real_pam_close_session(pamh, flags); +} + +/* Password Management API's */ + +int pam_chauthtok(pam_handle_t *pamh, int flags) +{ + static int (*real_pam_chauthtok)(pam_handle_t *, int); + CONFIRM_PAM_FUNCTION(pam_chauthtok, int, (pam_handle_t *, int), PAM_ABORT); + return real_pam_chauthtok(pamh, flags); +} diff --git a/Linux-PAM/dynamic/test.c b/Linux-PAM/dynamic/test.c new file mode 100644 index 00000000..35496fe4 --- /dev/null +++ b/Linux-PAM/dynamic/test.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <dlfcn.h> +#include <unistd.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +int main(int argc, char **argv) +{ + void *handle; + + handle = dlopen("./pam.so", RTLD_NOW); + if (handle == NULL) { + fprintf(stderr, "failed to load pam.so: %s\n", dlerror()); + exit(1); + } + + /* handle->XXX points to each of the PAM functions */ + + + if (dlclose(handle)) { + fprintf(stderr, "failed to unload pam.so: %s\n", dlerror()); + exit(1); + } + + exit(0); +} diff --git a/Linux-PAM/examples/Makefile b/Linux-PAM/examples/Makefile new file mode 100644 index 00000000..a55f1d21 --- /dev/null +++ b/Linux-PAM/examples/Makefile @@ -0,0 +1,54 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:35 hartmans Exp $ +# + +include ../Make.Rules + +PROGS = blank xsh check_user +SRCS = blank.c xsh.c check_user.c +PROGSUID = + +ifeq ($(WITH_LIBDEBUG),yes) + LIBSUFFIX=d +else + LIBSUFFIX= +endif + +CFLAGS += -I$(absolute_srcdir)/libpam_misc/include + +LOADLIBES = -L$(absolute_objdir)/libpam -L$(absolute_objdir)/libpamc \ + -L$(absolute_objdir)/libpam_misc -lpam -lpam_misc + +ifeq ($(STATIC_LIBPAM),yes) + ifneq ($(DYNAMIC),) + CFLAGS += $(CC_STATIC) + LOADLIBES += $(LIBDL) + endif +endif + +all: $(PROGS) + +check_user: check_user.o + $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) + +blank: blank.o + $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) + +xsh: xsh.o + $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) + +clean: + rm -f *.a *.so *.o *~ $(PROGS) $(PROGSUID) + rm -f *.a *.out *.o *.so + +# note, the programs are test programs, they should not be +# installed on your system! + +install: all + if [ -n "$(PROGS)" ]; then cp $(PROGS) ../bin ; fi + if [ -n "$(PROGSUID)" ]; then \ + $(INSTALL) -m 4555 $(PROGSUID) ../bin ; fi + +remove: + cd ../bin ; rm -f $(PROGS) $(PROGSUID) + for x in $(PROGS) $(PROGSUID) ; do rm -f ../bin/$$x ; done diff --git a/Linux-PAM/examples/blank.c b/Linux-PAM/examples/blank.c new file mode 100644 index 00000000..e4129b4b --- /dev/null +++ b/Linux-PAM/examples/blank.c @@ -0,0 +1,158 @@ +/* + * $Id: blank.c,v 1.1.1.1 2001/04/29 04:17:04 hartmans Exp $ + */ + +/* Andrew Morgan (morgan@parc.power.net) -- a self contained `blank' + * application + * + * I am not very proud of this code. It makes use of a possibly ill- + * defined pamh pointer to call pam_strerror() with. The reason that + * I was sloppy with this is historical (pam_strerror, prior to 0.59, + * did not require a pamh argument) and if this program is used as a + * model for anything, I should wish that you will take this error into + * account. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +/* ------ some local (static) functions ------- */ + +static void bail_out(pam_handle_t *pamh, int really, int code, const char *fn) +{ + fprintf(stderr,"==> called %s()\n got: `%s'\n", fn, + pam_strerror(pamh, code)); + if (really && code) + exit (1); +} + +/* ------ some static data objects ------- */ + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +/* ------- the application itself -------- */ + +int main(int argc, char **argv) +{ + pam_handle_t *pamh=NULL; + char *username=NULL; + int retcode; + + /* did the user call with a username as an argument ? */ + + if (argc > 2) { + fprintf(stderr,"usage: %s [username]\n",argv[0]); + } else if (argc == 2) { + username = argv[1]; + } + + /* initialize the Linux-PAM library */ + retcode = pam_start("blank", username, &conv, &pamh); + bail_out(pamh,1,retcode,"pam_start"); + + /* test the environment stuff */ + { +#define MAXENV 15 + const char *greek[MAXENV] = { + "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon", + "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu", + "l=zeta", "h=", "d", "k=xi" + }; + char **env; + int i; + + for (i=0; i<MAXENV; ++i) { + retcode = pam_putenv(pamh,greek[i]); + bail_out(pamh,0,retcode,"pam_putenv"); + } + env = pam_getenvlist(pamh); + if (env) + env = pam_misc_drop_env(env); + else + fprintf(stderr,"???\n"); + fprintf(stderr,"a test: c=[%s], j=[%s]\n" + , pam_getenv(pamh, "c"), pam_getenv(pamh, "j")); + } + + /* to avoid using goto we abuse a loop here */ + for (;;) { + /* authenticate the user --- `0' here, could have been PAM_SILENT + * | PAM_DISALLOW_NULL_AUTHTOK */ + + retcode = pam_authenticate(pamh, 0); + bail_out(pamh,0,retcode,"pam_authenticate"); + + /* has the user proved themself valid? */ + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: invalid request\n",argv[0]); + break; + } + + /* the user is valid, but should they have access at this + time? */ + + retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ + bail_out(pamh,0,retcode,"pam_acct_mgmt"); + + if (retcode == PAM_NEW_AUTHTOK_REQD) { + fprintf(stderr,"Application must request new password...\n"); + retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); + bail_out(pamh,0,retcode,"pam_chauthtok"); + } + + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: invalid request\n",argv[0]); + break; + } + + /* `0' could be as above */ + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); + bail_out(pamh,0,retcode,"pam_setcred1"); + + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem setting user credentials\n" + ,argv[0]); + break; + } + + /* open a session for the user --- `0' could be PAM_SILENT */ + retcode = pam_open_session(pamh,0); + bail_out(pamh,0,retcode,"pam_open_session"); + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem opening a session\n",argv[0]); + break; + } + + fprintf(stderr,"The user has been authenticated and `logged in'\n"); + + /* close a session for the user --- `0' could be PAM_SILENT + * it is possible that this pam_close_call is in another program.. + */ + + retcode = pam_close_session(pamh,0); + bail_out(pamh,0,retcode,"pam_close_session"); + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem closing a session\n",argv[0]); + break; + } + + retcode = pam_setcred(pamh, PAM_DELETE_CRED); + bail_out(pamh,0,retcode,"pam_setcred2"); + + break; /* don't go on for ever! */ + } + + /* close the Linux-PAM library */ + retcode = pam_end(pamh, PAM_SUCCESS); + pamh = NULL; + + bail_out(pamh,1,retcode,"pam_end"); + + exit(0); +} diff --git a/Linux-PAM/examples/check_user.c b/Linux-PAM/examples/check_user.c new file mode 100644 index 00000000..295d6715 --- /dev/null +++ b/Linux-PAM/examples/check_user.c @@ -0,0 +1,60 @@ +/* + $Id: check_user.c,v 1.1.1.1 2001/04/29 04:17:04 hartmans Exp $ + + This program was contributed by Shane Watts <shane@icarus.bofh.asn.au> + slight modifications by AGM. + + You need to add the following (or equivalent) to the /etc/pam.conf file. + # check authorization + check auth required pam_unix_auth.so + check account required pam_unix_acct.so +*/ + +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <stdio.h> + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +int main(int argc, char *argv[]) +{ + pam_handle_t *pamh=NULL; + int retval; + const char *user="nobody"; + + if(argc == 2) { + user = argv[1]; + } + + if(argc > 2) { + fprintf(stderr, "Usage: check_user [username]\n"); + exit(1); + } + + retval = pam_start("check", user, &conv, &pamh); + + if (retval == PAM_SUCCESS) + retval = pam_authenticate(pamh, 0); /* is user really user? */ + + if (retval == PAM_SUCCESS) + retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ + + /* This is where we have been authorized or not. */ + + if (retval == PAM_SUCCESS) { + fprintf(stdout, "Authenticated\n"); + } else { + fprintf(stdout, "Not Authenticated\n"); + } + + if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ + pamh = NULL; + fprintf(stderr, "check_user: failed to release authenticator\n"); + exit(1); + } + + return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ +} diff --git a/Linux-PAM/examples/vpass.c b/Linux-PAM/examples/vpass.c new file mode 100644 index 00000000..9a07ee38 --- /dev/null +++ b/Linux-PAM/examples/vpass.c @@ -0,0 +1,47 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> +#include <security/pam_appl.h> + +static int test_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + return 0; +} + +static struct pam_conv conv = { + test_conv, + NULL +}; + +int main(void) +{ + char *user; + pam_handle_t *pamh; + struct passwd *pw; + uid_t uid; + int res; + + uid = geteuid(); + pw = getpwuid(uid); + if (pw) { + user = pw->pw_name; + } else { + fprintf(stderr, "Invalid userid: %d\n", uid); + exit(1); + } + + pam_start("vpass", user, &conv, &pamh); + pam_set_item(pamh, PAM_TTY, "/dev/tty"); + if ((res = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { + fprintf(stderr, "Oops: %s\n", pam_strerror(pamh, res)); + exit(1); + } + + pam_end(pamh, res); + exit(0); +} + + diff --git a/Linux-PAM/examples/wrap_xsh.sh b/Linux-PAM/examples/wrap_xsh.sh new file mode 100755 index 00000000..af01697e --- /dev/null +++ b/Linux-PAM/examples/wrap_xsh.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export LD_PRELOAD=../libpam/libpam.so:../libpam_misc/libpam_misc.so +ldd ./xsh +./xsh "$@" + diff --git a/Linux-PAM/examples/xsh.c b/Linux-PAM/examples/xsh.c new file mode 100644 index 00000000..0e092402 --- /dev/null +++ b/Linux-PAM/examples/xsh.c @@ -0,0 +1,177 @@ +/* + * $Id: xsh.c,v 1.1.1.2 2002/09/15 20:08:35 hartmans Exp $ + */ + +/* Andrew Morgan (morgan@kernel.org) -- an example application + * that invokes a shell, based on blank.c */ + +#include <stdio.h> +#include <stdlib.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +#include <security/_pam_aconf.h> + +#include <pwd.h> +#include <sys/types.h> +#include <unistd.h> + +/* ------ some local (static) functions ------- */ + +static void bail_out(pam_handle_t *pamh,int really, int code, const char *fn) +{ + fprintf(stderr,"==> called %s()\n got: `%s'\n", fn, + pam_strerror(pamh,code)); + if (really && code) + exit (1); +} + +/* ------ some static data objects ------- */ + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +/* ------- the application itself -------- */ + +int main(int argc, char **argv) +{ + pam_handle_t *pamh=NULL; + const char *username=NULL; + const char *service="xsh"; + int retcode; + + /* did the user call with a username as an argument ? + * did they also */ + + if (argc > 3) { + fprintf(stderr,"usage: %s [username [service-name]]\n",argv[0]); + } + if ((argc >= 2) && (argv[1][0] != '-')) { + username = argv[1]; + } + if (argc == 3) { + service = argv[2]; + } + + /* initialize the Linux-PAM library */ + retcode = pam_start(service, username, &conv, &pamh); + bail_out(pamh,1,retcode,"pam_start"); + + /* fill in the RUSER and RHOST etc. fields */ + { + char buffer[100]; + struct passwd *pw; + const char *tty; + + pw = getpwuid(getuid()); + if (pw != NULL) { + retcode = pam_set_item(pamh, PAM_RUSER, pw->pw_name); + bail_out(pamh,1,retcode,"pam_set_item(PAM_RUSER)"); + } + + retcode = gethostname(buffer, sizeof(buffer)-1); + if (retcode) { + perror("failed to look up hostname"); + retcode = pam_end(pamh, PAM_ABORT); + bail_out(pamh,1,retcode,"pam_end"); + } + retcode = pam_set_item(pamh, PAM_RHOST, buffer); + bail_out(pamh,1,retcode,"pam_set_item(PAM_RHOST)"); + + tty = ttyname(fileno(stdin)); + if (tty) { + retcode = pam_set_item(pamh, PAM_TTY, tty); + bail_out(pamh,1,retcode,"pam_set_item(PAM_RHOST)"); + } + } + + /* to avoid using goto we abuse a loop here */ + for (;;) { + /* authenticate the user --- `0' here, could have been PAM_SILENT + * | PAM_DISALLOW_NULL_AUTHTOK */ + + retcode = pam_authenticate(pamh, 0); + bail_out(pamh,0,retcode,"pam_authenticate"); + + /* has the user proved themself valid? */ + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: invalid request\n",argv[0]); + break; + } + + /* the user is valid, but should they have access at this + time? */ + + retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ + bail_out(pamh,0,retcode,"pam_acct_mgmt"); + + if (retcode == PAM_NEW_AUTHTOK_REQD) { + fprintf(stderr,"Application must request new password...\n"); + retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); + bail_out(pamh,0,retcode,"pam_chauthtok"); + } + + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: invalid request\n",argv[0]); + break; + } + + /* `0' could be as above */ + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); + bail_out(pamh,0,retcode,"pam_setcred"); + + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem setting user credentials\n" + ,argv[0]); + break; + } + + /* open a session for the user --- `0' could be PAM_SILENT */ + retcode = pam_open_session(pamh,0); + bail_out(pamh,0,retcode,"pam_open_session"); + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem opening a session\n",argv[0]); + break; + } + + pam_get_item(pamh, PAM_USER, (const void **) &username); + fprintf(stderr, + "The user [%s] has been authenticated and `logged in'\n", + username); + + /* this is always a really bad thing for security! */ + system("/bin/sh"); + + /* close a session for the user --- `0' could be PAM_SILENT + * it is possible that this pam_close_call is in another program.. + */ + + retcode = pam_close_session(pamh,0); + bail_out(pamh,0,retcode,"pam_close_session"); + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem closing a session\n",argv[0]); + break; + } + + /* `0' could be as above */ + retcode = pam_setcred(pamh, PAM_DELETE_CRED); + bail_out(pamh,0,retcode,"pam_setcred"); + if (retcode != PAM_SUCCESS) { + fprintf(stderr,"%s: problem deleting user credentials\n" + ,argv[0]); + break; + } + + break; /* don't go on for ever! */ + } + + /* close the Linux-PAM library */ + retcode = pam_end(pamh, PAM_SUCCESS); + pamh = NULL; + bail_out(pamh,1,retcode,"pam_end"); + + exit(0); +} diff --git a/Linux-PAM/libpam/Makefile b/Linux-PAM/libpam/Makefile new file mode 100644 index 00000000..2c0813f7 --- /dev/null +++ b/Linux-PAM/libpam/Makefile @@ -0,0 +1,151 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:36 hartmans Exp $ +# +# + +include ../Make.Rules + +# need to tell libpam about the default directory for PAMs +MOREFLAGS=-D"DEFAULT_MODULE_PATH=\"$(SECUREDIR)/\"" + +ifeq ($(WITH_LIBDEBUG),yes) + LIBNAME=libpamd +else + LIBNAME=libpam +endif +VERSION=.$(MAJOR_REL) +MODIFICATION=.$(MINOR_REL) + +# --------------------------------------------- + +dummy: ../Make.Rules all + +# --------------------------------------------- + +CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS) \ + -DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \ + -DLIBPAM_VERSION_MINOR=$(MINOR_REL) + +# dynamic library names + +LIBPAM = $(LIBNAME).$(DYNTYPE) +LIBPAMNAME = $(LIBPAM)$(VERSION) +LIBPAMFULL = $(LIBPAMNAME)$(MODIFICATION) + +# static library name + +LIBPAMSTATIC = $(LIBNAME).a + +ifdef STATIC +@echo Did you mean to set STATIC\? +MODULES = $(shell cat ../modules/_static_module_objects) +STATICOBJ = pam_static.o +else +MODULES = +endif + +ifeq ($(WITH_MEMORY_DEBUG),yes) +EXTRAS += pam_malloc.o +endif + +LIBOBJECTS = pam_item.o pam_strerror.o pam_end.o pam_start.o pam_data.o \ + pam_delay.o pam_dispatch.o pam_handlers.o pam_misc.o \ + pam_account.o pam_auth.o pam_session.o pam_password.o \ + pam_env.o pam_log.o $(EXTRAS) + +ifeq ($(DYNAMIC_LIBPAM),yes) +# libpam.so needs -ldl, too. +DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS) $(STATICOBJ)) +ifeq ($(STATICOBJ),yes) +dynamic/pam_static.o: pam_static.c ../modules/_static_module_objects + $(CC) $(CFLAGS) -c pam_static.c -o $@ +endif +endif + +ifeq ($(STATIC_LIBPAM),yes) +SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ)) +ifdef STATICOBJ +static/pam_static.o: pam_static.c ../modules/_static_module_objects + $(CC) $(CFLAGS) -c pam_static.c -o $@ +endif +endif + +# --------------------------------------------- +## rules + +all: dirs $(LIBPAM) $(LIBPAMSTATIC) ../Make.Rules + +dirs: +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) dynamic +endif +ifeq ($(STATIC_LIBPAM),yes) + $(MKDIR) static +endif + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(LIBPAM): $(DLIBOBJECTS) +ifeq ($(DYNAMIC_LIBPAM),yes) + ifeq ($(USESONAME),yes) + $(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) \ + $(MODULES) $(LINKLIBS) + else + $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) + endif + ifeq ($(NEEDSONAME),yes) + rm -f $(LIBPAMFULL) + ln -sf $(LIBPAM) $(LIBPAMFULL) + rm -f $(LIBPAMNAME) + ln -sf $(LIBPAM) $(LIBPAMNAME) + endif +endif + +$(LIBPAMSTATIC): $(SLIBOBJECTS) +ifeq ($(STATIC_LIBPAM),yes) + ar cr $@ $(SLIBOBJECTS) $(MODULES) + $(RANLIB) $@ +endif + +install: all + $(MKDIR) $(FAKEROOT)$(INCLUDED) $(FAKEROOT)$(libdir) + $(INSTALL) -m 644 include/security/pam_appl.h $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/pam_modules.h $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/_pam_macros.h $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/_pam_types.h $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/_pam_compat.h $(FAKEROOT)$(INCLUDED) +ifdef MEMORY_DEBUG + $(INSTALL) -m 644 include/security/pam_malloc.h $(FAKEROOT)$(INCLUDED) +endif +ifeq ($(DYNAMIC_LIBPAM),yes) + $(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(libdir)/$(LIBPAMFULL) + $(LDCONFIG) + ifneq ($(DYNTYPE),"sl") + ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBPAM) ; \ + ln -sf $(LIBPAMNAME) $(LIBPAM) ) + endif +endif +ifeq ($(STATIC_LIBPAM),yes) + $(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(libdir) +endif + +remove: + rm -f $(FAKEROOT)$(INCLUDED)/_pam_types.h + rm -f $(FAKEROOT)$(INCLUDED)/_pam_macros.h + rm -f $(FAKEROOT)$(INCLUDED)/pam_appl.h + rm -f $(FAKEROOT)$(INCLUDED)/pam_modules.h + rm -f $(FAKEROOT)$(INCLUDED)/pam_malloc.h + rm -f $(FAKEROOT)$(libdir)/$(LIBPAM).* + rm -f $(FAKEROOT)$(libdir)/$(LIBPAM) + $(LDCONFIG) + rm -f $(FAKEROOT)$(libdir)/$(LIBPAMSTATIC) + +clean: + rm -f a.out core *~ static/*.o dynamic/*.o + rm -f *.a *.o *.so ./include/security/*~ + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi diff --git a/Linux-PAM/libpam/include/security/_pam_compat.h b/Linux-PAM/libpam/include/security/_pam_compat.h new file mode 100644 index 00000000..b66a5479 --- /dev/null +++ b/Linux-PAM/libpam/include/security/_pam_compat.h @@ -0,0 +1,122 @@ +#ifndef _PAM_COMPAT_H +#define _PAM_COMPAT_H + +/* + * $Id: _pam_compat.h,v 1.1.1.1 2001/04/29 04:17:10 hartmans Exp $ + * + * This file was contributed by Derrick J Brashear <shadow@dementia.org> + * slight modification by Brad M. Garcia <bgarcia@fore.com> + * + * A number of operating systems have started to implement PAM. + * unfortunately, they have a different set of numeric values for + * certain constants. This file is included for compatibility's sake. + */ + +/* Solaris uses different constants. We redefine to those here */ +#if defined(solaris) || (defined(__SVR4) && defined(sun)) + +#ifndef _SECURITY__PAM_TYPES_H + +# ifdef _SECURITY_PAM_MODULES_H + +/* flags for pam_chauthtok() */ +# undef PAM_PRELIM_CHECK +# define PAM_PRELIM_CHECK 0x1 + +# undef PAM_UPDATE_AUTHTOK +# define PAM_UPDATE_AUTHTOK 0x2 + +# endif /* _SECURITY_PAM_MODULES_H */ + +#else /* _SECURITY__PAM_TYPES_H */ + +/* generic for pam_* functions */ +# undef PAM_SILENT +# define PAM_SILENT 0x80000000 + +/* flags for pam_setcred() */ +# undef PAM_ESTABLISH_CRED +# define PAM_ESTABLISH_CRED 0x1 + +# undef PAM_DELETE_CRED +# define PAM_DELETE_CRED 0x2 + +# undef PAM_REINITIALIZE_CRED +# define PAM_REINITIALIZE_CRED 0x4 + +# undef PAM_REFRESH_CRED +# define PAM_REFRESH_CRED 0x8 + +/* another binary incompatibility comes from the return codes! */ + +# undef PAM_CONV_ERR +# define PAM_CONV_ERR 6 + +# undef PAM_PERM_DENIED +# define PAM_PERM_DENIED 7 + +# undef PAM_MAXTRIES +# define PAM_MAXTRIES 8 + +# undef PAM_AUTH_ERR +# define PAM_AUTH_ERR 9 + +# undef PAM_NEW_AUTHTOK_REQD +# define PAM_NEW_AUTHTOK_REQD 10 + +# undef PAM_CRED_INSUFFICIENT +# define PAM_CRED_INSUFFICIENT 11 + +# undef PAM_AUTHINFO_UNAVAIL +# define PAM_AUTHINFO_UNAVAIL 12 + +# undef PAM_USER_UNKNOWN +# define PAM_USER_UNKNOWN 13 + +# undef PAM_CRED_UNAVAIL +# define PAM_CRED_UNAVAIL 14 + +# undef PAM_CRED_EXPIRED +# define PAM_CRED_EXPIRED 15 + +# undef PAM_CRED_ERR +# define PAM_CRED_ERR 16 + +# undef PAM_ACCT_EXPIRED +# define PAM_ACCT_EXPIRED 17 + +# undef PAM_AUTHTOK_EXPIRED +# define PAM_AUTHTOK_EXPIRED 18 + +# undef PAM_SESSION_ERR +# define PAM_SESSION_ERR 19 + +# undef PAM_AUTHTOK_ERR +# define PAM_AUTHTOK_ERR 20 + +# undef PAM_AUTHTOK_RECOVERY_ERR +# define PAM_AUTHTOK_RECOVERY_ERR 21 + +# undef PAM_AUTHTOK_LOCK_BUSY +# define PAM_AUTHTOK_LOCK_BUSY 22 + +# undef PAM_AUTHTOK_DISABLE_AGING +# define PAM_AUTHTOK_DISABLE_AGING 23 + +# undef PAM_NO_MODULE_DATA +# define PAM_NO_MODULE_DATA 24 + +# undef PAM_IGNORE +# define PAM_IGNORE 25 + +# undef PAM_ABORT +# define PAM_ABORT 26 + +# undef PAM_TRY_AGAIN +# define PAM_TRY_AGAIN 27 + +#endif /* _SECURITY__PAM_TYPES_H */ + +#endif /* defined(solaris) || (defined(__SVR4) && defined(sun)) */ + +#endif /* _PAM_COMPAT_H */ diff --git a/Linux-PAM/libpam/include/security/_pam_macros.h b/Linux-PAM/libpam/include/security/_pam_macros.h new file mode 100644 index 00000000..2827fabf --- /dev/null +++ b/Linux-PAM/libpam/include/security/_pam_macros.h @@ -0,0 +1,187 @@ +#ifndef PAM_MACROS_H +#define PAM_MACROS_H + +/* + * All kind of macros used by PAM, but usable in some other + * programs too. + * Organized by Cristian Gafton <gafton@redhat.com> + */ + +/* a 'safe' version of strdup */ + +#include <string.h> +#include <stdlib.h> + +#define x_strdup(s) ( (s) ? strdup(s):NULL ) + +/* Good policy to strike out passwords with some characters not just + free the memory */ + +#define _pam_overwrite(x) \ +do { \ + register char *__xx__; \ + if ((__xx__=(x))) \ + while (*__xx__) \ + *__xx__++ = '\0'; \ +} while (0) + +/* + * Don't just free it, forget it too. + */ + +#define _pam_drop(X) \ +do { \ + if (X) { \ + free(X); \ + X=NULL; \ + } \ +} while (0) + +#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \ +do { \ + int reply_i; \ + \ + for (reply_i=0; reply_i<replies; ++reply_i) { \ + if (reply[reply_i].resp) { \ + _pam_overwrite(reply[reply_i].resp); \ + free(reply[reply_i].resp); \ + } \ + } \ + if (reply) \ + free(reply); \ +} while (0) + +/* some debugging code */ + +#ifdef DEBUG + +/* + * This provides the necessary function to do debugging in PAM. + * Cristian Gafton <gafton@redhat.com> + */ + +#include <stdio.h> +#include <sys/types.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +/* + * This is for debugging purposes ONLY. DO NOT use on live systems !!! + * You have been warned :-) - CG + * + * to get automated debugging to the log file, it must be created manually. + * _PAM_LOGFILE must exist, mode 666 + */ + +#ifndef _PAM_LOGFILE +#define _PAM_LOGFILE "/tmp/pam-debug.log" +#endif + +static void _pam_output_debug_info(const char *file, const char *fn + , const int line) +{ + FILE *logfile; + int must_close = 1, fd; + +#ifdef O_NOFOLLOW + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { +#else + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { +#endif + if (!(logfile = fdopen(fd,"a"))) { + logfile = stderr; + must_close = 0; + close(fd); + } + } else { + logfile = stderr; + must_close = 0; + } + fprintf(logfile,"[%s:%s(%d)] ",file, fn, line); + fflush(logfile); + if (must_close) + fclose(logfile); +} + +static void _pam_output_debug(const char *format, ...) +{ + va_list args; + FILE *logfile; + int must_close = 1, fd; + + va_start(args, format); + +#ifdef O_NOFOLLOW + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { +#else + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { +#endif + if (!(logfile = fdopen(fd,"a"))) { + logfile = stderr; + must_close = 0; + close(fd); + } + } else { + logfile = stderr; + must_close = 0; + } + vfprintf(logfile, format, args); + fprintf(logfile, "\n"); + fflush(logfile); + if (must_close) + fclose(logfile); + + va_end(args); +} + +#define D(x) do { \ + _pam_output_debug_info(__FILE__, __FUNCTION__, __LINE__); \ + _pam_output_debug x ; \ +} while (0) + +#define _pam_show_mem(X,XS) do { \ + int i; \ + register unsigned char *x; \ + x = (unsigned char *)X; \ + fprintf(stderr, " <start at %p>\n", X); \ + for (i = 0; i < XS ; ++x, ++i) { \ + fprintf(stderr, " %02X. <%p:%02X>\n", i, x, *x); \ + } \ + fprintf(stderr, " <end for %p after %d bytes>\n", X, XS); \ +} while (0) + +#define _pam_show_reply(/* struct pam_response * */reply, /* int */replies) \ +do { \ + int reply_i; \ + setbuf(stderr, NULL); \ + fprintf(stderr, "array at %p of size %d\n",reply,replies); \ + fflush(stderr); \ + if (reply) { \ + for (reply_i = 0; reply_i < replies; reply_i++) { \ + fprintf(stderr, " elem# %d at %p: resp = %p, retcode = %d\n", \ + reply_i, reply+reply_i, reply[reply_i].resp, \ + reply[reply_i].resp, _retcode); \ + fflush(stderr); \ + if (reply[reply_i].resp) { \ + fprintf(stderr, " resp[%d] = '%s'\n", \ + strlen(reply[reply_i].resp), reply[reply_i].resp); \ + fflush(stderr); \ + } \ + } \ + } \ + fprintf(stderr, "done here\n"); \ + fflush(stderr); \ +} while (0) + +#else + +#define D(x) do { } while (0) +#define _pam_show_mem(X,XS) do { } while (0) +#define _pam_show_reply(reply, replies) do { } while (0) + +#endif /* DEBUG */ + +#endif /* PAM_MACROS_H */ diff --git a/Linux-PAM/libpam/include/security/_pam_types.h b/Linux-PAM/libpam/include/security/_pam_types.h new file mode 100644 index 00000000..5bc4a43d --- /dev/null +++ b/Linux-PAM/libpam/include/security/_pam_types.h @@ -0,0 +1,324 @@ +/* + * <security/_pam_types.h> + * + * $Id: _pam_types.h,v 1.1.1.1 2001/04/29 04:17:10 hartmans Exp $ + * + * This file defines all of the types common to the Linux-PAM library + * applications and modules. + * + * Note, the copyright+license information is at end of file. + * + * Created: 1996/3/5 by AGM + */ + +#ifndef _SECURITY__PAM_TYPES_H +#define _SECURITY__PAM_TYPES_H + +#ifndef __LIBPAM_VERSION +# define __LIBPAM_VERSION __libpam_version +#endif +extern unsigned int __libpam_version; + +/* + * include local definition for POSIX - NULL + */ + +#include <locale.h> + +/* This is a blind structure; users aren't allowed to see inside a + * pam_handle_t, so we don't define struct pam_handle here. This is + * defined in a file private to the PAM library. (i.e., it's private + * to PAM service modules, too!) */ + +typedef struct pam_handle pam_handle_t; + +/* ----------------- The Linux-PAM return values ------------------ */ + +#define PAM_SUCCESS 0 /* Successful function return */ +#define PAM_OPEN_ERR 1 /* dlopen() failure when dynamically */ + /* loading a service module */ +#define PAM_SYMBOL_ERR 2 /* Symbol not found */ +#define PAM_SERVICE_ERR 3 /* Error in service module */ +#define PAM_SYSTEM_ERR 4 /* System error */ +#define PAM_BUF_ERR 5 /* Memory buffer error */ +#define PAM_PERM_DENIED 6 /* Permission denied */ +#define PAM_AUTH_ERR 7 /* Authentication failure */ +#define PAM_CRED_INSUFFICIENT 8 /* Can not access authentication data */ + /* due to insufficient credentials */ +#define PAM_AUTHINFO_UNAVAIL 9 /* Underlying authentication service */ + /* can not retrieve authenticaiton */ + /* information */ +#define PAM_USER_UNKNOWN 10 /* User not known to the underlying */ + /* authenticaiton module */ +#define PAM_MAXTRIES 11 /* An authentication service has */ + /* maintained a retry count which has */ + /* been reached. No further retries */ + /* should be attempted */ +#define PAM_NEW_AUTHTOK_REQD 12 /* New authentication token required. */ + /* This is normally returned if the */ + /* machine security policies require */ + /* that the password should be changed */ + /* beccause the password is NULL or it */ + /* has aged */ +#define PAM_ACCT_EXPIRED 13 /* User account has expired */ +#define PAM_SESSION_ERR 14 /* Can not make/remove an entry for */ + /* the specified session */ +#define PAM_CRED_UNAVAIL 15 /* Underlying authentication service */ + /* can not retrieve user credentials */ + /* unavailable */ +#define PAM_CRED_EXPIRED 16 /* User credentials expired */ +#define PAM_CRED_ERR 17 /* Failure setting user credentials */ +#define PAM_NO_MODULE_DATA 18 /* No module specific data is present */ +#define PAM_CONV_ERR 19 /* Conversation error */ +#define PAM_AUTHTOK_ERR 20 /* Authentication token manipulation error */ +#define PAM_AUTHTOK_RECOVER_ERR 21 /* Authentication information */ + /* cannot be recovered */ +#define PAM_AUTHTOK_LOCK_BUSY 22 /* Authentication token lock busy */ +#define PAM_AUTHTOK_DISABLE_AGING 23 /* Authentication token aging disabled */ +#define PAM_TRY_AGAIN 24 /* Preliminary check by password service */ +#define PAM_IGNORE 25 /* Ingore underlying account module */ + /* regardless of whether the control */ + /* flag is required, optional, or sufficient */ +#define PAM_ABORT 26 /* Critical error (?module fail now request) */ +#define PAM_AUTHTOK_EXPIRED 27 /* user's authentication token has expired */ +#define PAM_MODULE_UNKNOWN 28 /* module is not known */ + +#define PAM_BAD_ITEM 29 /* Bad item passed to pam_*_item() */ +#define PAM_CONV_AGAIN 30 /* conversation function is event driven + and data is not available yet */ +#define PAM_INCOMPLETE 31 /* please call this function again to + complete authentication stack. Before + calling again, verify that conversation + is completed */ + +/* + * Add new #define's here - take care to also extend the libpam code: + * pam_strerror() and "libpam/pam_tokens.h" . + */ + +#define _PAM_RETURN_VALUES 32 /* this is the number of return values */ + + +/* ---------------------- The Linux-PAM flags -------------------- */ + +/* Authentication service should not generate any messages */ +#define PAM_SILENT 0x8000U + +/* Note: these flags are used by pam_authenticate{,_secondary}() */ + +/* The authentication service should return PAM_AUTH_ERROR if the + * user has a null authentication token */ +#define PAM_DISALLOW_NULL_AUTHTOK 0x0001U + +/* Note: these flags are used for pam_setcred() */ + +/* Set user credentials for an authentication service */ +#define PAM_ESTABLISH_CRED 0x0002U + +/* Delete user credentials associated with an authentication service */ +#define PAM_DELETE_CRED 0x0004U + +/* Reinitialize user credentials */ +#define PAM_REINITIALIZE_CRED 0x0008U + +/* Extend lifetime of user credentials */ +#define PAM_REFRESH_CRED 0x0010U + +/* Note: these flags are used by pam_chauthtok */ + +/* The password service should only update those passwords that have + * aged. If this flag is not passed, the password service should + * update all passwords. */ +#define PAM_CHANGE_EXPIRED_AUTHTOK 0x0020U + +/* ------------------ The Linux-PAM item types ------------------- */ + +/* these defines are used by pam_set_item() and pam_get_item() */ + +#define PAM_SERVICE 1 /* The service name */ +#define PAM_USER 2 /* The user name */ +#define PAM_TTY 3 /* The tty name */ +#define PAM_RHOST 4 /* The remote host name */ +#define PAM_CONV 5 /* The pam_conv structure */ + +/* missing entries found in <security/pam_modules.h> for modules only! */ + +#define PAM_RUSER 8 /* The remote user name */ +#define PAM_USER_PROMPT 9 /* the prompt for getting a username */ +#define PAM_FAIL_DELAY 10 /* app supplied function to override failure + delays */ + +/* ---------- Common Linux-PAM application/module PI ----------- */ + +extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item); +extern int pam_get_item(const pam_handle_t *pamh, int item_type, + const void **item); +extern const char *pam_strerror(pam_handle_t *pamh, int errnum); + +extern int pam_putenv(pam_handle_t *pamh, const char *name_value); +extern const char *pam_getenv(pam_handle_t *pamh, const char *name); +extern char **pam_getenvlist(pam_handle_t *pamh); + +/* ---------- Common Linux-PAM application/module PI ----------- */ + +/* + * here are some proposed error status definitions for the + * 'error_status' argument used by the cleanup function associated + * with data items they should be logically OR'd with the error_status + * of the latest return from libpam -- new with .52 and positive + * impression from Sun although not official as of 1996/9/4 + * [generally the other flags are to be found in pam_modules.h] + */ + +#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */ + +/* + * here we define an externally (by apps or modules) callable function + * that primes the libpam library to delay when a stacked set of + * modules results in a failure. In the case of PAM_SUCCESS this delay + * is ignored. + * + * Note, the pam_[gs]et_item(... PAM_FAIL_DELAY ...) can be used to set + * a function pointer which can override the default fail-delay behavior. + * This item was added to accommodate event driven programs that need to + * manage delays more carefully. The function prototype for this data + * item is + * void (*fail_delay)(int status, unsigned int delay, void *appdata_ptr); + */ + +#define HAVE_PAM_FAIL_DELAY +extern int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay); + +#include <syslog.h> +#ifndef LOG_AUTHPRIV +# ifdef LOG_PRIV +# define LOG_AUTHPRIV LOG_PRIV +# endif /* LOG_PRIV */ +#endif /* !LOG_AUTHPRIV */ + +#ifdef MEMORY_DEBUG +/* + * this defines some macros that keep track of what memory has been + * allocated and indicates leakage etc... It should not be included in + * production application/modules. + */ +#include <security/pam_malloc.h> +#endif + +/* ------------ The Linux-PAM conversation structures ------------ */ + +/* Message styles */ + +#define PAM_PROMPT_ECHO_OFF 1 +#define PAM_PROMPT_ECHO_ON 2 +#define PAM_ERROR_MSG 3 +#define PAM_TEXT_INFO 4 + +/* Linux-PAM specific types */ + +#define PAM_RADIO_TYPE 5 /* yes/no/maybe conditionals */ + +/* This is for server client non-human interaction.. these are NOT + part of the X/Open PAM specification. */ + +#define PAM_BINARY_PROMPT 7 + +/* maximum size of messages/responses etc.. (these are mostly + arbitrary so Linux-PAM should handle longer values). */ + +#define PAM_MAX_NUM_MSG 32 +#define PAM_MAX_MSG_SIZE 512 +#define PAM_MAX_RESP_SIZE 512 + +/* Used to pass prompting text, error messages, or other informatory + * text to the user. This structure is allocated and freed by the PAM + * library (or loaded module). */ + +struct pam_message { + int msg_style; + const char *msg; +}; + +/* if the pam_message.msg_style = PAM_BINARY_PROMPT + the 'pam_message.msg' is a pointer to a 'const *' for the following + pseudo-structure. When used with a PAM_BINARY_PROMPT, the returned + pam_response.resp pointer points to an object with the following + structure: + + struct { + u32 length; # network byte order + unsigned char type; + unsigned char data[length-5]; + }; + + The 'libpamc' library is designed around this flavor of + message and should be used to handle this flavor of msg_style. + */ + +/* Used to return the user's response to the PAM library. This + structure is allocated by the application program, and free()'d by + the Linux-PAM library (or calling module). */ + +struct pam_response { + char *resp; + int resp_retcode; /* currently un-used, zero expected */ +}; + +/* The actual conversation structure itself */ + +struct pam_conv { + int (*conv)(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr); + void *appdata_ptr; +}; + +#ifndef LINUX_PAM +/* + * the following few lines represent a hack. They are there to make + * the Linux-PAM headers more compatible with the Sun ones, which have a + * less strictly separated notion of module specific and application + * specific definitions. + */ +#include <security/pam_appl.h> +#include <security/pam_modules.h> +#endif + + +/* ... adapted from the pam_appl.h file created by Theodore Ts'o and + * + * Copyright Theodore Ts'o, 1996. All rights reserved. + * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org>, 1996-8 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#endif /* _SECURITY__PAM_TYPES_H */ + diff --git a/Linux-PAM/libpam/include/security/pam_appl.h b/Linux-PAM/libpam/include/security/pam_appl.h new file mode 100644 index 00000000..21bc2212 --- /dev/null +++ b/Linux-PAM/libpam/include/security/pam_appl.h @@ -0,0 +1,92 @@ +/* + * <security/pam_appl.h> + * + * This header file collects definitions for the PAM API --- that is, + * public interface between the PAM library and an application program + * that wishes to use it. + * + * Note, the copyright information is at end of file. + * + * Created: 15-Jan-96 by TYT + * Last modified: 1996/3/5 by AGM + * + * $Id: pam_appl.h,v 1.1.1.1 2001/04/29 04:17:11 hartmans Exp $ + */ + +#ifndef _SECURITY_PAM_APPL_H +#define _SECURITY_PAM_APPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <security/_pam_types.h> /* Linux-PAM common defined types */ + +/* -------------- The Linux-PAM Framework layer API ------------- */ + +extern int pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh); +extern int pam_end(pam_handle_t *pamh, int pam_status); + +/* Authentication API's */ + +extern int pam_authenticate(pam_handle_t *pamh, int flags); +extern int pam_setcred(pam_handle_t *pamh, int flags); + +/* Account Management API's */ + +extern int pam_acct_mgmt(pam_handle_t *pamh, int flags); + +/* Session Management API's */ + +extern int pam_open_session(pam_handle_t *pamh, int flags); +extern int pam_close_session(pam_handle_t *pamh, int flags); + +/* Password Management API's */ + +extern int pam_chauthtok(pam_handle_t *pamh, int flags); + +#ifdef __cplusplus +} +#endif + +/* take care of any compatibility issues */ +#include <security/_pam_compat.h> + +/* + * Copyright Theodore Ts'o, 1996. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#endif /* _SECURITY_PAM_APPL_H */ diff --git a/Linux-PAM/libpam/include/security/pam_malloc.h b/Linux-PAM/libpam/include/security/pam_malloc.h new file mode 100644 index 00000000..60a38857 --- /dev/null +++ b/Linux-PAM/libpam/include/security/pam_malloc.h @@ -0,0 +1,71 @@ +/* + * $Id: pam_malloc.h,v 1.1.1.2 2002/09/15 20:08:40 hartmans Exp $ + */ + +/* + * This file (via the use of macros) defines a wrapper for the malloc + * family of calls. It logs where the memory was requested and also + * where it was free()'d and keeps a list of currently requested memory. + * + * It is hoped that it will provide some help in locating memory leaks. + */ + +#ifndef PAM_MALLOC_H +#define PAM_MALLOC_H + +/* these are the macro definitions for the stdlib.h memory functions */ + +#define malloc(s) pam_malloc(s,__FILE__,__FUNCTION__,__LINE__) +#define calloc(n,s) pam_calloc(n,s,__FILE__,__FUNCTION__,__LINE__) +#define free(x) pam_free(x,__FILE__,__FUNCTION__,__LINE__) +/* #define memalign(a,s) pam_memalign(a,s,__FILE__,__FUNCTION__,__LINE__) */ +#define realloc(x,s) pam_realloc(x,s,__FILE__,__FUNCTION__,__LINE__) +/* #define valloc(s) pam_valloc(s,__FILE__,__FUNCTION__,__LINE__) */ +/* #define alloca(s) pam_alloca(s,__FILE__,__FUNCTION__,__LINE__) */ +#define exit(i) pam_exit(i,__FILE__,__FUNCTION__,__LINE__) +#define strdup(s) pam_strdup(s,__FILE__,__FUNCTION__,__LINE__) + +/* these are the prototypes for the wrapper functions */ + +#include <sys/types.h> + +extern void *pam_malloc(size_t s,const char *,const char *, int); +extern void *pam_calloc(size_t n,size_t s,const char *,const char *, int); +extern void pam_free(void *x,const char *,const char *, int); +extern void *pam_memalign(size_t a,size_t s + ,const char *,const char *, int); +extern void *pam_realloc(void *x,size_t s,const char *,const char *, int); +extern void *pam_valloc(size_t s,const char *,const char *, int); +extern void *pam_alloca(size_t s,const char *,const char *, int); +extern void pam_exit(int i,const char *,const char *, int); +extern char *pam_strdup(const char *,const char *,const char *, int); + +/* these are the flags used to turn on and off diagnostics */ + +#define PAM_MALLOC_LEAKED 01 +#define PAM_MALLOC_REQUEST 02 +#define PAM_MALLOC_FREE 04 +#define PAM_MALLOC_EXCH (PAM_MALLOC_FREED|PAM_MALLOC_EXCH) +#define PAM_MALLOC_RESIZE 010 +#define PAM_MALLOC_FAIL 020 +#define PAM_MALLOC_NULL 040 +#define PAM_MALLOC_VERIFY 0100 +#define PAM_MALLOC_FUNC 0200 +#define PAM_MALLOC_PAUSE 0400 +#define PAM_MALLOC_STOP 01000 + +#define PAM_MALLOC_ALL 0777 + +#define PAM_MALLOC_DEFAULT \ + (PAM_MALLOC_LEAKED|PAM_MALLOC_PAUSE|PAM_MALLOC_FAIL) + +#include <stdio.h> + +extern FILE *pam_malloc_outfile; /* defaults to stdout */ + +/* how much output do you want? */ + +extern int pam_malloc_flags; +extern int pam_malloc_delay_length; /* how long to pause on errors */ + +#endif /* PAM_MALLOC_H */ diff --git a/Linux-PAM/libpam/include/security/pam_modules.h b/Linux-PAM/libpam/include/security/pam_modules.h new file mode 100644 index 00000000..0fac9994 --- /dev/null +++ b/Linux-PAM/libpam/include/security/pam_modules.h @@ -0,0 +1,169 @@ +/* + * <security/pam_modules.h> + * + * $Id: pam_modules.h,v 1.1.1.1 2001/04/29 04:17:11 hartmans Exp $ + * + */ + +#ifndef _SECURITY_PAM_MODULES_H +#define _SECURITY_PAM_MODULES_H + +#include <security/_pam_types.h> /* Linux-PAM common defined types */ + +/* these defines are used by pam_set_item() and pam_get_item() and are + * in addition to those found in <security/_pam_types.h> */ + +#define PAM_AUTHTOK 6 /* The authentication token (password) */ +#define PAM_OLDAUTHTOK 7 /* The old authentication token */ + +/* -------------- The Linux-PAM Module PI ------------- */ + +extern int pam_set_data(pam_handle_t *pamh, const char *module_data_name, + void *data, + void (*cleanup)(pam_handle_t *pamh, void *data, + int error_status)); +extern int pam_get_data(const pam_handle_t *pamh, + const char *module_data_name, const void **data); + +extern int pam_get_user(pam_handle_t *pamh, const char **user + , const char *prompt); + +#ifdef PAM_STATIC + +#define PAM_EXTERN static + +struct pam_module { + const char *name; /* Name of the module */ + + /* These are function pointers to the module's key functions. */ + + int (*pam_sm_authenticate)(pam_handle_t *pamh, int flags, + int argc, const char **argv); + int (*pam_sm_setcred)(pam_handle_t *pamh, int flags, + int argc, const char **argv); + int (*pam_sm_acct_mgmt)(pam_handle_t *pamh, int flags, + int argc, const char **argv); + int (*pam_sm_open_session)(pam_handle_t *pamh, int flags, + int argc, const char **argv); + int (*pam_sm_close_session)(pam_handle_t *pamh, int flags, + int argc, const char **argv); + int (*pam_sm_chauthtok)(pam_handle_t *pamh, int flags, + int argc, const char **argv); +}; + +#else /* !PAM_STATIC */ + +#define PAM_EXTERN extern + +#endif /* PAM_STATIC */ + +/* Lots of files include pam_modules.h that don't need these + * declared. However, when they are declared static, they + * need to be defined later. So we have to protect C files + * that include these without wanting these functions defined.. */ + +#if (defined(PAM_STATIC) && defined(PAM_SM_AUTH)) || !defined(PAM_STATIC) + +/* Authentication API's */ +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv); +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv); + +#endif /*(defined(PAM_STATIC) && defined(PAM_SM_AUTH)) + || !defined(PAM_STATIC)*/ + +#if (defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) || !defined(PAM_STATIC) + +/* Account Management API's */ +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv); + +#endif /*(defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) + || !defined(PAM_STATIC)*/ + +#if (defined(PAM_STATIC) && defined(PAM_SM_SESSION)) || !defined(PAM_STATIC) + +/* Session Management API's */ +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv); + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv); + +#endif /*(defined(PAM_STATIC) && defined(PAM_SM_SESSION)) + || !defined(PAM_STATIC)*/ + +#if (defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) || !defined(PAM_STATIC) + +/* Password Management API's */ +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv); + +#endif /*(defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) + || !defined(PAM_STATIC)*/ + +/* The following two flags are for use across the Linux-PAM/module + * interface only. The Application is not permitted to use these + * tokens. + * + * The password service should only perform preliminary checks. No + * passwords should be updated. */ +#define PAM_PRELIM_CHECK 0x4000 + +/* The password service should update passwords Note: PAM_PRELIM_CHECK + * and PAM_UPDATE_AUTHTOK cannot both be set simultaneously! */ +#define PAM_UPDATE_AUTHTOK 0x2000 + + +/* + * here are some proposed error status definitions for the + * 'error_status' argument used by the cleanup function associated + * with data items they should be logically OR'd with the error_status + * of the latest return from libpam -- new with .52 and positive + * impression from Sun although not official as of 1996/9/4 there are + * others in _pam_types.h -- they are for common module/app use. + */ + +#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */ + +/* take care of any compatibility issues */ +#include <security/_pam_compat.h> + +/* Copyright (C) Theodore Ts'o, 1996. + * Copyright (C) Andrew Morgan, 1996-8. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the + * GNU GPL are required INSTEAD OF the above restrictions. (This + * clause is necessary due to a potential bad interaction between the + * GNU GPL and the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#endif /* _SECURITY_PAM_MODULES_H */ + diff --git a/Linux-PAM/libpam/pam_account.c b/Linux-PAM/libpam/pam_account.c new file mode 100644 index 00000000..71e04f15 --- /dev/null +++ b/Linux-PAM/libpam/pam_account.c @@ -0,0 +1,23 @@ +/* pam_account.c - PAM Account Management */ + +#include <stdio.h> + +#include "pam_private.h" + +int pam_acct_mgmt(pam_handle_t *pamh, int flags) +{ + int retval; + + D(("called")); + + IF_NO_PAMH("pam_acct_mgmt", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT); + + return retval; +} diff --git a/Linux-PAM/libpam/pam_auth.c b/Linux-PAM/libpam/pam_auth.c new file mode 100644 index 00000000..f8dd8c0d --- /dev/null +++ b/Linux-PAM/libpam/pam_auth.c @@ -0,0 +1,68 @@ +/* + * pam_auth.c -- PAM authentication + * + * $Id: pam_auth.c,v 1.1.1.1 2001/04/29 04:17:04 hartmans Exp $ + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "pam_private.h" + +int pam_authenticate(pam_handle_t *pamh, int flags) +{ + int retval; + + D(("pam_authenticate called")); + + IF_NO_PAMH("pam_authenticate", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + if (pamh->former.choice == PAM_NOT_STACKED) { + _pam_sanitize(pamh); + _pam_start_timer(pamh); /* we try to make the time for a failure + independent of the time it takes to + fail */ + } + + retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE); + + if (retval != PAM_INCOMPLETE) { + _pam_sanitize(pamh); + _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ + D(("pam_authenticate exit")); + } else { + D(("will resume when ready")); + } + + return retval; +} + +int pam_setcred(pam_handle_t *pamh, int flags) +{ + int retval; + + D(("pam_setcred called")); + + IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + if (! flags) { + flags = PAM_ESTABLISH_CRED; + } + + retval = _pam_dispatch(pamh, flags, PAM_SETCRED); + + D(("pam_setcred exit")); + + return retval; +} diff --git a/Linux-PAM/libpam/pam_data.c b/Linux-PAM/libpam/pam_data.c new file mode 100644 index 00000000..635357cd --- /dev/null +++ b/Linux-PAM/libpam/pam_data.c @@ -0,0 +1,123 @@ +/* pam_data.c */ + +/* + * $Id: pam_data.c,v 1.1.1.1 2001/04/29 04:17:04 hartmans Exp $ + */ + +#include <stdlib.h> +#include <string.h> + +#include "pam_private.h" + +static struct pam_data *_pam_locate_data(const pam_handle_t *pamh, + const char *name) +{ + struct pam_data *data; + + D(("called")); + + IF_NO_PAMH("_pam_locate_data", pamh, NULL); + + data = pamh->data; + + while (data) { + if (!strcmp(data->name, name)) { + return data; + } + data = data->next; + } + + return NULL; +} + +int pam_set_data( + pam_handle_t *pamh, + const char *module_data_name, + void *data, + void (*cleanup)(pam_handle_t *pamh, void *data, int error_status)) +{ + struct pam_data *data_entry; + + D(("called")); + + IF_NO_PAMH("pam_set_data", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_APP(pamh)) { + D(("called from application!?")); + return PAM_SYSTEM_ERR; + } + + /* first check if there is some data already. If so clean it up */ + + if ((data_entry = _pam_locate_data(pamh, module_data_name))) { + if (data_entry->cleanup) { + data_entry->cleanup(pamh, data_entry->data, + PAM_DATA_REPLACE | PAM_SUCCESS ); + } + } else if ((data_entry = malloc(sizeof(*data_entry)))) { + char *tname; + + if ((tname = _pam_strdup(module_data_name)) == NULL) { + _pam_system_log(LOG_CRIT, "pam_set_data: no memory for data name"); + _pam_drop(data_entry); + return PAM_BUF_ERR; + } + data_entry->next = pamh->data; + pamh->data = data_entry; + data_entry->name = tname; + } else { + _pam_system_log(LOG_CRIT, "pam_set_data: cannot allocate data entry"); + return PAM_BUF_ERR; + } + + data_entry->data = data; /* note this could be NULL */ + data_entry->cleanup = cleanup; + + return PAM_SUCCESS; +} + +int pam_get_data( + const pam_handle_t *pamh, + const char *module_data_name, + const void **datap) +{ + struct pam_data *data; + + D(("called")); + + IF_NO_PAMH("pam_get_data", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_APP(pamh)) { + D(("called from application!?")); + return PAM_SYSTEM_ERR; + } + + data = _pam_locate_data(pamh, module_data_name); + if (data) { + *datap = data->data; + return PAM_SUCCESS; + } + + return PAM_NO_MODULE_DATA; +} + +void _pam_free_data(pam_handle_t *pamh, int status) +{ + struct pam_data *last; + struct pam_data *data; + + D(("called")); + + IF_NO_PAMH("_pam_free_data", pamh, /* no return value for void fn */); + data = pamh->data; + + while (data) { + last = data; + data = data->next; + if (last->cleanup) { + last->cleanup(pamh, last->data, status); + } + _pam_drop(last->name); + _pam_drop(last); + } +} diff --git a/Linux-PAM/libpam/pam_delay.c b/Linux-PAM/libpam/pam_delay.c new file mode 100644 index 00000000..b2b7f0cb --- /dev/null +++ b/Linux-PAM/libpam/pam_delay.c @@ -0,0 +1,159 @@ +/* + * pam_delay.c + * + * Copyright (c) Andrew G. Morgan <morgan@kernel.org> 1996-9 + * All rights reserved. + * + * $Id: pam_delay.c,v 1.1.1.2 2002/09/15 20:08:36 hartmans Exp $ + * + */ + +/* + * This is a simple implementation of a delay on failure mechanism; an + * attempt to overcome authentication-time attacks in a simple manner. + */ + +#include <unistd.h> +#include <time.h> +#include "pam_private.h" + +/* ********************************************************************** + * initialize the time as unset, this is set on the return from the + * authenticating pair of of the libpam pam_XXX calls. + */ + +void _pam_reset_timer(pam_handle_t *pamh) +{ + D(("setting pamh->fail_delay.set to FALSE")); + pamh->fail_delay.set = PAM_FALSE; +} + +/* ********************************************************************** + * this function sets the start time for possible delayed failing. + * + * Eventually, it may set the timer so libpam knows how long the program + * has already been executing. Currently, this value is used to seed + * a pseudo-random number generator... + */ + +void _pam_start_timer(pam_handle_t *pamh) +{ + pamh->fail_delay.begin = time(NULL); + D(("starting timer...")); +} + +/* ******************************************************************* + * Compute a pseudo random time. The value is base*(1 +/- 1/5) where + * the distribution is pseudo gausian (the sum of three evenly + * distributed random numbers -- central limit theorem and all ;^) The + * linear random numbers are based on a formulae given in Knuth's + * Seminumerical recipies that was reproduced in `Numerical Recipies + * in C'. It is *not* a cryptographically strong generator, but it is + * probably "good enough" for our purposes here. + * + * /dev/random might be a better place to look for some numbers... + */ + +static unsigned int _pam_rand(unsigned int seed) +{ +#define N1 1664525 +#define N2 1013904223 + return N1*seed + N2; +} + +static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base) +{ + int i; + double sum; + unsigned int ans; + + for (sum=i=0; i<3; ++i) { + seed = _pam_rand(seed); + sum += (double) ((seed / 10) % 1000000); + } + sum = (sum/3.)/1e6 - .5; /* rescale */ + ans = (unsigned int) ( base*(1.+sum) ); + D(("random number: base=%u -> ans=%u\n", base, ans)); + + return ans; +} + +/* ********************************************************************** + * the following function sleeps for a random time. The actual time + * slept is computed above.. It is based on the requested time but will + * differ by up to +/- 25%. + */ + +void _pam_await_timer(pam_handle_t *pamh, int status) +{ + unsigned int delay; + D(("waiting?...")); + + delay = _pam_compute_delay(pamh->fail_delay.begin, + pamh->fail_delay.delay); + if (pamh->fail_delay.delay_fn_ptr) { + union { + const void *value; + void (*fn)(int, unsigned, void *); + } hack_fn_u; + void *appdata_ptr; + + if (pamh->pam_conversation) { + appdata_ptr = pamh->pam_conversation->appdata_ptr; + } else { + appdata_ptr = NULL; + } + + /* always call the applications delay function, even if + the delay is zero - indicate status */ + hack_fn_u.value = pamh->fail_delay.delay_fn_ptr; + hack_fn_u.fn(status, delay, appdata_ptr); + + } else if (status != PAM_SUCCESS && pamh->fail_delay.set) { + + D(("will wait %u usec", delay)); + + if (delay > 0) { + struct timeval tval; + + tval.tv_sec = delay / 1000000; + tval.tv_usec = delay % 1000000; + select(0, NULL, NULL, NULL, &tval); + } + } + + _pam_reset_timer(pamh); + D(("waiting done")); +} + +/* ********************************************************************** + * this function is known to both the module and the application, it + * keeps a running score of the largest-requested delay so far, as + * specified by either modules or an application. + */ + +int pam_fail_delay(pam_handle_t *pamh, unsigned int usec) +{ + unsigned int largest; + + IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR); + + D(("setting delay to %u",usec)); + + if (pamh->fail_delay.set) { + largest = pamh->fail_delay.delay; + } else { + pamh->fail_delay.set = PAM_TRUE; + largest = 0; + } + + D(("largest = %u",largest)); + + if (largest < usec) { + D(("resetting largest delay")); + pamh->fail_delay.delay = usec; + } + + return PAM_SUCCESS; +} + diff --git a/Linux-PAM/libpam/pam_dispatch.c b/Linux-PAM/libpam/pam_dispatch.c new file mode 100644 index 00000000..2c82e81d --- /dev/null +++ b/Linux-PAM/libpam/pam_dispatch.c @@ -0,0 +1,378 @@ +/* pam_dispatch.c - handles module function dispatch */ + +/* + * Copyright (c) 1998 Andrew G. Morgan <morgan@kernel.org> + * + * $Id: pam_dispatch.c,v 1.1.1.2 2002/09/15 20:08:36 hartmans Exp $ + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "pam_private.h" + +/* + * this is the return code we return when a function pointer is NULL + * or, the handler structure indicates a broken module config line + */ +#define PAM_MUST_FAIL_CODE PAM_PERM_DENIED + +/* impression codes - this gives some sense to the logical choices */ +#define _PAM_UNDEF 0 +#define _PAM_POSITIVE +1 +#define _PAM_NEGATIVE -1 + +/* frozen chain required codes */ +#define _PAM_PLEASE_FREEZE 0 +#define _PAM_MAY_BE_FROZEN 1 +#define _PAM_MUST_BE_FROZEN 2 + +/* + * walk a stack of modules. Interpret the administrator's instructions + * when combining the return code of each module. + */ + +static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h, + _pam_boolean resumed, int use_cached_chain) +{ + int depth, impression, status, skip_depth; + + IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR); + + if (h == NULL) { + const char *service=NULL; + + (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); + _pam_system_log(LOG_ERR, "no modules loaded for `%s' service", + service ? service:"<unknown>" ); + service = NULL; + return PAM_MUST_FAIL_CODE; + } + + /* if we are recalling this module stack because a former call did + not complete, we restore the state of play from pamh. */ + if (resumed) { + skip_depth = pamh->former.depth; + status = pamh->former.status; + impression = pamh->former.impression; + /* forget all that */ + pamh->former.impression = _PAM_UNDEF; + pamh->former.status = PAM_MUST_FAIL_CODE; + pamh->former.depth = 0; + } else { + skip_depth = 0; + impression = _PAM_UNDEF; + status = PAM_MUST_FAIL_CODE; + } + + /* Loop through module logic stack */ + for (depth=0 ; h != NULL ; h = h->next, ++depth) { + int retval, cached_retval, action; + + /* skip leading modules if they have already returned */ + if (depth < skip_depth) { + continue; + } + + /* attempt to call the module */ + if (h->func == NULL) { + D(("module function is not defined, indicating failure")); + retval = PAM_MODULE_UNKNOWN; + } else { + D(("passing control to module...")); + retval = h->func(pamh, flags, h->argc, h->argv); + D(("module returned: %s", pam_strerror(pamh, retval))); + if (h->must_fail) { + D(("module poorly listed in PAM config; forcing failure")); + retval = PAM_MUST_FAIL_CODE; + } + } + + /* + * PAM_INCOMPLETE return is special. It indicates that the + * module wants to wait for the application before continuing. + * In order to return this, the module will have saved its + * state so it can resume from an equivalent position when it + * is called next time. (This was added as of 0.65) + */ + if (retval == PAM_INCOMPLETE) { + pamh->former.impression = impression; + pamh->former.status = status; + pamh->former.depth = depth; + + D(("module %d returned PAM_INCOMPLETE", depth)); + return retval; + } + + /* + * use_cached_chain is how we ensure that the setcred/close_session + * and chauthtok(2) modules are called in the same order as they did + * when they were invoked as auth/open_session/chauthtok(1). This + * feature was added in 0.75 to make the behavior of pam_setcred + * sane. It was debugged by release 0.76. + */ + if (use_cached_chain != _PAM_PLEASE_FREEZE) { + + /* a former stack execution should have frozen the chain */ + + cached_retval = *(h->cached_retval_p); + if (cached_retval == _PAM_INVALID_RETVAL) { + + /* This may be a problem condition. It implies that + the application is running setcred, close_session, + chauthtok(2nd) without having first run + authenticate, open_session, chauthtok(1st) + [respectively]. */ + + D(("use_cached_chain is set to [%d]," + " but cached_retval == _PAM_INVALID_RETVAL", + use_cached_chain)); + + /* In the case of close_session and setcred there is a + backward compatibility reason for allowing this, in + the chauthtok case we have encountered a bug in + libpam! */ + + if (use_cached_chain == _PAM_MAY_BE_FROZEN) { + /* (not ideal) force non-frozen stack control. */ + cached_retval = retval; + } else { + D(("BUG in libpam -" + " chain is required to be frozen but isn't")); + + /* cached_retval is already _PAM_INVALID_RETVAL */ + } + } + } else { + /* this stack execution is defining the frozen chain */ + cached_retval = h->cached_retval = retval; + } + + /* verify that the return value is a valid one */ + if ((cached_retval < PAM_SUCCESS) + || (cached_retval >= _PAM_RETURN_VALUES)) { + + retval = PAM_MUST_FAIL_CODE; + action = _PAM_ACTION_BAD; + } else { + /* We treat the current retval with some respect. It may + (for example, in the case of setcred) have a value that + needs to be propagated to the user. We want to use the + cached_retval to determine the modules to be executed + in the stacked chain, but we want to treat each + non-ignored module in the cached chain as now being + 'required'. We only need to treat the, + _PAM_ACTION_IGNORE, _PAM_ACTION_IS_JUMP and + _PAM_ACTION_RESET actions specially. */ + + action = h->actions[cached_retval]; + } + + D(("use_cached_chain=%d action=%d cached_retval=%d retval=%d", + use_cached_chain, action, cached_retval, retval)); + + /* decide what to do */ + switch (action) { + case _PAM_ACTION_RESET: + + impression = _PAM_UNDEF; + status = PAM_MUST_FAIL_CODE; + break; + + case _PAM_ACTION_OK: + case _PAM_ACTION_DONE: + + if ( impression == _PAM_UNDEF + || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) { + impression = _PAM_POSITIVE; + status = retval; + } + if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) { + goto decision_made; + } + break; + + case _PAM_ACTION_BAD: + case _PAM_ACTION_DIE: +#ifdef PAM_FAIL_NOW_ON + if ( cached_retval == PAM_ABORT ) { + impression = _PAM_NEGATIVE; + status = PAM_PERM_DENIED; + goto decision_made; + } +#endif /* PAM_FAIL_NOW_ON */ + if ( impression != _PAM_NEGATIVE ) { + impression = _PAM_NEGATIVE; + status = retval; + } + if ( action == _PAM_ACTION_DIE ) { + goto decision_made; + } + break; + + case _PAM_ACTION_IGNORE: + break; + + /* if we get here, we expect action is a positive number -- + this is what the ...JUMP macro checks. */ + + default: + if ( _PAM_ACTION_IS_JUMP(action) ) { + + /* If we are evaluating a cached chain, we treat this + module as required (aka _PAM_ACTION_OK) as well as + executing the jump. */ + + if (use_cached_chain) { + if (impression == _PAM_UNDEF + || (impression == _PAM_POSITIVE + && status == PAM_SUCCESS) ) { + impression = _PAM_POSITIVE; + status = retval; + } + } + + /* this means that we need to skip #action stacked modules */ + do { + h = h->next; + } while ( --action > 0 && h != NULL ); + + /* note if we try to skip too many modules action is + still non-zero and we snag the next if. */ + } + + /* this case is a syntax error: we can't succeed */ + if (action) { + D(("action syntax error")); + impression = _PAM_NEGATIVE; + status = PAM_MUST_FAIL_CODE; + } + } + } + +decision_made: /* by getting here we have made a decision */ + + /* Sanity check */ + if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) { + D(("caught on sanity check -- this is probably a config error!")); + status = PAM_MUST_FAIL_CODE; + } + + /* We have made a decision about the modules executed */ + return status; +} + +/* + * This function translates the module dispatch request into a pointer + * to the stack of modules that will actually be run. the + * _pam_dispatch_aux() function (above) is responsible for walking the + * module stack. + */ + +int _pam_dispatch(pam_handle_t *pamh, int flags, int choice) +{ + struct handler *h = NULL; + int retval, use_cached_chain; + _pam_boolean resumed; + + IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from a module!?")); + return PAM_SYSTEM_ERR; + } + + /* Load all modules, resolve all symbols */ + + if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) { + _pam_system_log(LOG_ERR, "unable to dispatch function"); + return retval; + } + + use_cached_chain = _PAM_PLEASE_FREEZE; + + switch (choice) { + case PAM_AUTHENTICATE: + h = pamh->handlers.conf.authenticate; + break; + case PAM_SETCRED: + h = pamh->handlers.conf.setcred; + use_cached_chain = _PAM_MAY_BE_FROZEN; + break; + case PAM_ACCOUNT: + h = pamh->handlers.conf.acct_mgmt; + break; + case PAM_OPEN_SESSION: + h = pamh->handlers.conf.open_session; + break; + case PAM_CLOSE_SESSION: + h = pamh->handlers.conf.close_session; + use_cached_chain = _PAM_MAY_BE_FROZEN; + break; + case PAM_CHAUTHTOK: + h = pamh->handlers.conf.chauthtok; + if (flags & PAM_UPDATE_AUTHTOK) { + use_cached_chain = _PAM_MUST_BE_FROZEN; + } + break; + default: + _pam_system_log(LOG_ERR, "undefined fn choice; %d", choice); + return PAM_ABORT; + } + + if (h == NULL) { /* there was no handlers.conf... entry; will use + * handlers.other... */ + switch (choice) { + case PAM_AUTHENTICATE: + h = pamh->handlers.other.authenticate; + break; + case PAM_SETCRED: + h = pamh->handlers.other.setcred; + break; + case PAM_ACCOUNT: + h = pamh->handlers.other.acct_mgmt; + break; + case PAM_OPEN_SESSION: + h = pamh->handlers.other.open_session; + break; + case PAM_CLOSE_SESSION: + h = pamh->handlers.other.close_session; + break; + case PAM_CHAUTHTOK: + h = pamh->handlers.other.chauthtok; + break; + } + } + + /* Did a module return an "incomplete state" last time? */ + if (pamh->former.choice != PAM_NOT_STACKED) { + if (pamh->former.choice != choice) { + _pam_system_log(LOG_ERR, + "application failed to re-exec stack [%d:%d]", + pamh->former.choice, choice); + return PAM_ABORT; + } + resumed = PAM_TRUE; + } else { + resumed = PAM_FALSE; + } + + __PAM_TO_MODULE(pamh); + + /* call the list of module functions */ + retval = _pam_dispatch_aux(pamh, flags, h, resumed, use_cached_chain); + resumed = PAM_FALSE; + + __PAM_TO_APP(pamh); + + /* Should we recall where to resume next time? */ + if (retval == PAM_INCOMPLETE) { + D(("module [%d] returned PAM_INCOMPLETE")); + pamh->former.choice = choice; + } else { + pamh->former.choice = PAM_NOT_STACKED; + } + + return retval; +} + diff --git a/Linux-PAM/libpam/pam_end.c b/Linux-PAM/libpam/pam_end.c new file mode 100644 index 00000000..890d18f1 --- /dev/null +++ b/Linux-PAM/libpam/pam_end.c @@ -0,0 +1,77 @@ +/* pam_end.c */ + +/* + * $Id: pam_end.c,v 1.1.1.1 2001/04/29 04:17:05 hartmans Exp $ + */ + +#include <stdlib.h> + +#include "pam_private.h" + +int pam_end(pam_handle_t *pamh, int pam_status) +{ + int ret; + + D(("entering pam_end()")); + + IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + /* first liberate the modules (it is not inconcevible that the + modules may need to use the service_name etc. to clean up) */ + + _pam_free_data(pamh, pam_status); + + /* now drop all modules */ + + if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) { + return ret; /* error occurred */ + } + + /* from this point we cannot call the modules any more. Free the remaining + memory used by the Linux-PAM interface */ + + _pam_drop_env(pamh); /* purge the environment */ + + _pam_overwrite(pamh->authtok); /* blank out old token */ + _pam_drop(pamh->authtok); + + _pam_overwrite(pamh->oldauthtok); /* blank out old token */ + _pam_drop(pamh->oldauthtok); + + _pam_overwrite(pamh->former.prompt); + _pam_drop(pamh->former.prompt); /* drop saved prompt */ + + _pam_overwrite(pamh->service_name); + _pam_drop(pamh->service_name); + + _pam_overwrite(pamh->user); + _pam_drop(pamh->user); + + _pam_overwrite(pamh->prompt); + _pam_drop(pamh->prompt); /* prompt for pam_get_user() */ + + _pam_overwrite(pamh->tty); + _pam_drop(pamh->tty); + + _pam_overwrite(pamh->rhost); + _pam_drop(pamh->rhost); + + _pam_overwrite(pamh->ruser); + _pam_drop(pamh->ruser); + + _pam_drop(pamh->pam_conversation); + pamh->fail_delay.delay_fn_ptr = NULL; + + /* and finally liberate the memory for the pam_handle structure */ + + _pam_drop(pamh); + + D(("exiting pam_end() successfully")); + + return PAM_SUCCESS; +} diff --git a/Linux-PAM/libpam/pam_env.c b/Linux-PAM/libpam/pam_env.c new file mode 100644 index 00000000..0f718ae3 --- /dev/null +++ b/Linux-PAM/libpam/pam_env.c @@ -0,0 +1,390 @@ +/* + * pam_env.c + * + * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997 + * All rights reserved. + * + * This file was written from a "hint" provided by the people at SUN. + * and the X/Open XSSO draft of March 1997. + * + * $Id: pam_env.c,v 1.1.1.1 2001/04/29 04:17:05 hartmans Exp $ + */ + +#include <string.h> +#include <stdlib.h> +#ifdef sunos +#define memmove(x,y,z) bcopy(y,x,z) +#endif + +#include "pam_private.h" + +/* helper functions */ + +#ifdef DEBUG +static void _pam_dump_env(pam_handle_t *pamh) +{ + int i; + + D(("Listing environment of pamh=%p", pamh)); + D(("pamh->env = %p", pamh->env)); + D(("environment entries used = %d [of %d allocated]" + , pamh->env->requested, pamh->env->entries)); + + for (i=0; i<pamh->env->requested; ++i) { + _pam_output_debug(">%-3d [%9p]:[%s]" + , i, pamh->env->list[i], pamh->env->list[i]); + } + _pam_output_debug("*NOTE* the last item should be (nil)"); +} +#else +#define _pam_dump_env(x) +#endif + +/* + * Create the environment + */ + +int _pam_make_env(pam_handle_t *pamh) +{ + D(("called.")); + + IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT); + + /* + * get structure memory + */ + + pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ)); + if (pamh->env == NULL) { + _pam_system_log(LOG_CRIT, "_pam_make_env: out of memory"); + return PAM_BUF_ERR; + } + + /* + * get list memory + */ + + pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) ); + if (pamh->env->list == NULL) { + _pam_system_log(LOG_CRIT, "_pam_make_env: no memory for list"); + _pam_drop(pamh->env); + return PAM_BUF_ERR; + } + + /* + * fill entries in pamh->env + */ + + pamh->env->entries = PAM_ENV_CHUNK; + pamh->env->requested = 1; + pamh->env->list[0] = NULL; + + _pam_dump_env(pamh); /* only active when debugging */ + + return PAM_SUCCESS; +} + +/* + * purge the environment + */ + +void _pam_drop_env(pam_handle_t *pamh) +{ + D(("called.")); + IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */); + + if (pamh->env != NULL) { + int i; + /* we will only purge the pamh->env->requested number of elements */ + + for (i=pamh->env->requested-1; i-- > 0; ) { + D(("dropping #%3d>%s<", i, pamh->env->list[i])); + _pam_overwrite(pamh->env->list[i]); /* clean */ + _pam_drop(pamh->env->list[i]); /* forget */ + } + pamh->env->requested = 0; + pamh->env->entries = 0; + _pam_drop(pamh->env->list); /* forget */ + _pam_drop(pamh->env); /* forget */ + } else { + D(("no environment present in pamh?")); + } +} + +/* + * Return the item number of the given variable = first 'length' chars + * of 'name_value'. Since this is a static function, it is safe to + * assume its supplied arguments are well defined. + */ + +static int _pam_search_env(const struct pam_environ *env + , const char *name_value, int length) +{ + int i; + + for (i=env->requested-1; i-- > 0; ) { + if (strncmp(name_value,env->list[i],length) == 0 + && env->list[i][length] == '=') { + + return i; /* Got it! */ + + } + } + + return -1; /* no luck */ +} + +/* + * externally visible functions + */ + +/* + * pam_putenv(): Add/replace/delete a PAM-environment variable. + * + * Add/replace: + * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0") + * + * delete: + * name_value = "NAME" + */ + +int pam_putenv(pam_handle_t *pamh, const char *name_value) +{ + int l2eq, item, retval; + + D(("called.")); + IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT); + + if (name_value == NULL) { + _pam_system_log(LOG_ERR, "pam_putenv: no variable indicated"); + return PAM_PERM_DENIED; + } + + /* + * establish if we are setting or deleting; scan for '=' + */ + + for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq); + if (l2eq <= 0) { + _pam_system_log(LOG_ERR, "pam_putenv: bad variable"); + return PAM_BAD_ITEM; + } + + /* + * Look first for environment. + */ + + if (pamh->env == NULL || pamh->env->list == NULL) { + _pam_system_log(LOG_ERR, "pam_putenv: no env%s found", + pamh->env == NULL ? "":"-list"); + return PAM_ABORT; + } + + /* find the item to replace */ + + item = _pam_search_env(pamh->env, name_value, l2eq); + + if (name_value[l2eq]) { /* (re)setting */ + + if (item == -1) { /* new variable */ + D(("adding item: %s", name_value)); + /* enough space? */ + if (pamh->env->entries <= pamh->env->requested) { + register int i; + register char **tmp; + + /* get some new space */ + tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK + , sizeof(char *) ); + if (tmp == NULL) { + /* nothing has changed - old env intact */ + _pam_system_log(LOG_CRIT, + "pam_putenv: cannot grow environment"); + return PAM_BUF_ERR; + } + + /* copy old env-item pointers/forget old */ + for (i=0; i<pamh->env->requested; ++i) { + tmp[i] = pamh->env->list[i]; + pamh->env->list[i] = NULL; + } + + /* drop old list and replace with new */ + _pam_drop(pamh->env->list); + pamh->env->list = tmp; + pamh->env->entries += PAM_ENV_CHUNK; + + D(("resized env list")); + _pam_dump_env(pamh); /* only when debugging */ + } + + item = pamh->env->requested-1; /* old last item (NULL) */ + + /* add a new NULL entry at end; increase counter */ + pamh->env->list[pamh->env->requested++] = NULL; + + } else { /* replace old */ + D(("replacing item: %s\n with: %s" + , pamh->env->list[item], name_value)); + _pam_overwrite(pamh->env->list[item]); + _pam_drop(pamh->env->list[item]); + } + + /* + * now we have a place to put the new env-item, insert at 'item' + */ + + pamh->env->list[item] = _pam_strdup(name_value); + if (pamh->env->list[item] != NULL) { + _pam_dump_env(pamh); /* only when debugging */ + return PAM_SUCCESS; + } + + /* something went wrong; we should delete the item - fall through */ + + retval = PAM_BUF_ERR; /* an error occurred */ + } else { + retval = PAM_SUCCESS; /* we requested delete */ + } + + /* getting to here implies we are deleting an item */ + + if (item < 0) { + _pam_system_log(LOG_ERR, "pam_putenv: delete non-existent entry; %s", + name_value); + return PAM_BAD_ITEM; + } + + /* + * remove item: purge memory; reset counter; resize [; display-env] + */ + + D(("deleting: env#%3d:[%s]", item, pamh->env->list[item])); + _pam_overwrite(pamh->env->list[item]); + _pam_drop(pamh->env->list[item]); + --(pamh->env->requested); + D(("mmove: item[%d]+%d -> item[%d]" + , item+1, ( pamh->env->requested - item ), item)); + (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1] + , ( pamh->env->requested - item )*sizeof(char *) ); + + _pam_dump_env(pamh); /* only when debugging */ + + /* + * deleted. + */ + + return retval; +} + +/* + * Return the value of the requested environment variable + */ + +const char *pam_getenv(pam_handle_t *pamh, const char *name) +{ + int item; + + D(("called.")); + IF_NO_PAMH("pam_getenv", pamh, NULL); + + if (name == NULL) { + _pam_system_log(LOG_ERR, "pam_getenv: no variable indicated"); + return NULL; + } + + if (pamh->env == NULL || pamh->env->list == NULL) { + _pam_system_log(LOG_ERR, "pam_getenv: no env%s found", + pamh->env == NULL ? "":"-list" ); + return NULL; + } + + /* find the requested item */ + + item = _pam_search_env(pamh->env, name, strlen(name)); + if (item != -1) { + + D(("env-item: %s, found!", name)); + return (pamh->env->list[item] + 1 + strlen(name)); + + } else { + + D(("env-item: %s, not found", name)); + return NULL; + + } +} + +static char **_copy_env(pam_handle_t *pamh) +{ + char **dump; + int i = pamh->env->requested; /* reckon size of environment */ + char *const *env = pamh->env->list; + + D(("now get some memory for dump")); + + /* allocate some memory for this (plus the null tail-pointer) */ + dump = (char **) calloc(i, sizeof(char *)); + D(("dump = %p", dump)); + if (dump == NULL) { + return NULL; + } + + /* now run through entries and copy the variables over */ + dump[--i] = NULL; + while (i-- > 0) { + D(("env[%d]=`%s'", i,env[i])); + dump[i] = _pam_strdup(env[i]); + D(("->dump[%d]=`%s'", i,dump[i])); + if (dump[i] == NULL) { + /* out of memory */ + + while (dump[++i]) { + _pam_overwrite(dump[i]); + _pam_drop(dump[i]); + } + return NULL; + } + } + + env = NULL; /* forget now */ + + /* return transcribed environment */ + return dump; +} + +char **pam_getenvlist(pam_handle_t *pamh) +{ + int i; + + D(("called.")); + IF_NO_PAMH("pam_getenvlist", pamh, NULL); + + if (pamh->env == NULL || pamh->env->list == NULL) { + _pam_system_log(LOG_ERR, "pam_getenvlist: no env%s found", + pamh->env == NULL ? "":"-list" ); + return NULL; + } + + /* some quick checks */ + + if (pamh->env->requested > pamh->env->entries) { + _pam_system_log(LOG_ERR, "pam_getenvlist: environment corruption"); + _pam_dump_env(pamh); /* only active when debugging */ + return NULL; + } + + for (i=pamh->env->requested-1; i-- > 0; ) { + if (pamh->env->list[i] == NULL) { + _pam_system_log(LOG_ERR, "pam_getenvlist: environment broken"); + _pam_dump_env(pamh); /* only active when debugging */ + return NULL; /* somehow we've broken the environment!? */ + } + } + + /* Seems fine; copy environment */ + + _pam_dump_env(pamh); /* only active when debugging */ + + return _copy_env(pamh); +} diff --git a/Linux-PAM/libpam/pam_handlers.c b/Linux-PAM/libpam/pam_handlers.c new file mode 100644 index 00000000..d00f1842 --- /dev/null +++ b/Linux-PAM/libpam/pam_handlers.c @@ -0,0 +1,897 @@ +/* pam_handlers.c -- pam config file parsing and module loading */ + +/* + * created by Marc Ewing. + * Currently maintained by Andrew G. Morgan <morgan@kernel.org> + * + * $Id: pam_handlers.c,v 1.1.1.2 2002/09/15 20:08:37 hartmans Exp $ + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#ifdef PAM_DYNAMIC +# ifdef PAM_SHL +# include <dl.h> +# else /* PAM_SHL */ +# include <dlfcn.h> +# endif /* PAM_SHL */ +#endif /* PAM_DYNAMIC */ + +#include "pam_private.h" + +/* If not required, define as nothing */ +#ifndef SHLIB_SYM_PREFIX +# define SHLIB_SYM_PREFIX "" +#endif + +#define BUF_SIZE 1024 +#define MODULE_CHUNK 4 +#define UNKNOWN_MODULE_PATH "<*unknown module path*>" + +static int _pam_assemble_line(FILE *f, char *buf, int buf_len); + +static void _pam_free_handlers_aux(struct handler **hp); + +static int _pam_add_handler(pam_handle_t *pamh + , int must_fail, int other, int type + , int *actions, const char *mod_path + , int argc, char **argv, int argvlen); + +/* Values for module type */ + +#define PAM_T_AUTH 1 +#define PAM_T_SESS 2 +#define PAM_T_ACCT 4 +#define PAM_T_PASS 8 + +static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f + , const char *known_service /* specific file */ +#ifdef PAM_READ_BOTH_CONFS + , int not_other +#endif /* PAM_READ_BOTH_CONFS */ + ) +{ + char buf[BUF_SIZE]; + int x; /* read a line from the FILE *f ? */ + /* + * read a line from the configuration (FILE *) f + */ + while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) { + char *tok, *nexttok=NULL; + const char *this_service; + const char *mod_path; + int module_type, actions[_PAM_RETURN_VALUES]; + int other; /* set if module is for PAM_DEFAULT_SERVICE */ + int res; /* module added successfully? */ + int must_fail=0; /* a badly formatted line must fail when used */ + int argc; + char **argv; + int argvlen; + + D(("_pam_init_handler: LINE: %s", buf)); + if (known_service != NULL) { + nexttok = buf; + /* No service field: all lines are for the known service. */ + this_service = known_service; + } else { + this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok); + } + +#ifdef PAM_READ_BOTH_CONFS + if (not_other) + other = 0; + else +#endif /* PAM_READ_BOTH_CONFS */ + other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE); + + /* accept "service name" or PAM_DEFAULT_SERVICE modules */ + if (!_pam_strCMP(this_service, pamh->service_name) || other) { + /* This is a service we are looking for */ + D(("_pam_init_handlers: Found PAM config entry for: %s" + , this_service)); + + tok = _pam_StrTok(NULL, " \n\t", &nexttok); + if (!_pam_strCMP("auth", tok)) { + module_type = PAM_T_AUTH; + } else if (!_pam_strCMP("session", tok)) { + module_type = PAM_T_SESS; + } else if (!_pam_strCMP("account", tok)) { + module_type = PAM_T_ACCT; + } else if (!_pam_strCMP("password", tok)) { + module_type = PAM_T_PASS; + } else { + /* Illegal module type */ + D(("_pam_init_handlers: bad module type: %s", tok)); + _pam_system_log(LOG_ERR, "(%s) illegal module type: %s", + this_service, tok); + module_type = PAM_T_AUTH; /* most sensitive */ + must_fail = 1; /* install as normal but fail when dispatched */ + } + D(("Using %s config entry: %s", must_fail?"BAD ":"", tok)); + + /* reset the actions to .._UNDEF's -- this is so that + we can work out which entries are not yet set (for default). */ + { + int i; + for (i=0; i<_PAM_RETURN_VALUES; + actions[i++] = _PAM_ACTION_UNDEF); + } + tok = _pam_StrTok(NULL, " \n\t", &nexttok); + if (!_pam_strCMP("required", tok)) { + D(("*PAM_F_REQUIRED*")); + actions[PAM_SUCCESS] = _PAM_ACTION_OK; + actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; + actions[PAM_IGNORE] = _PAM_ACTION_IGNORE; + _pam_set_default_control(actions, _PAM_ACTION_BAD); + } else if (!_pam_strCMP("requisite", tok)) { + D(("*PAM_F_REQUISITE*")); + actions[PAM_SUCCESS] = _PAM_ACTION_OK; + actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; + actions[PAM_IGNORE] = _PAM_ACTION_IGNORE; + _pam_set_default_control(actions, _PAM_ACTION_DIE); + } else if (!_pam_strCMP("optional", tok)) { + D(("*PAM_F_OPTIONAL*")); + actions[PAM_SUCCESS] = _PAM_ACTION_OK; + actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; + _pam_set_default_control(actions, _PAM_ACTION_IGNORE); + } else if (!_pam_strCMP("sufficient", tok)) { + D(("*PAM_F_SUFFICIENT*")); + actions[PAM_SUCCESS] = _PAM_ACTION_DONE; + actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE; + _pam_set_default_control(actions, _PAM_ACTION_IGNORE); + } else { + D(("will need to parse %s", tok)); + _pam_parse_control(actions, tok); + /* by default the default is to treat as failure */ + _pam_set_default_control(actions, _PAM_ACTION_BAD); + } + + tok = _pam_StrTok(NULL, " \n\t", &nexttok); + if (tok != NULL) { + mod_path = tok; + D(("mod_path = %s",mod_path)); + } else { + /* no module name given */ + D(("_pam_init_handlers: no module name supplied")); + _pam_system_log(LOG_ERR, + "(%s) no module name supplied", this_service); + mod_path = NULL; + must_fail = 1; + } + + /* nexttok points to remaining arguments... */ + + if (nexttok != NULL) { + D(("list: %s",nexttok)); + argvlen = _pam_mkargv(nexttok, &argv, &argc); + D(("argvlen = %d",argvlen)); + } else { /* there are no arguments so fix by hand */ + D(("_pam_init_handlers: empty argument list")); + argvlen = argc = 0; + argv = NULL; + } + +#ifdef DEBUG + { + int y; + + D(("CONF%s: %s%s %d %s %d" + , must_fail?"<*will fail*>":"" + , this_service, other ? "(backup)":"" + , module_type + , mod_path, argc)); + for (y = 0; y < argc; y++) { + D(("CONF: %s", argv[y])); + } + for (y = 0; y<_PAM_RETURN_VALUES; ++y) { + D(("RETURN %s(%d) -> %d %s", + _pam_token_returns[y], y, actions[y], + actions[y]>0 ? "jump": + _pam_token_actions[-actions[y]])); + } + } +#endif + + res = _pam_add_handler(pamh, must_fail, other + , module_type, actions, mod_path + , argc, argv, argvlen); + if (res != PAM_SUCCESS) { + _pam_system_log(LOG_ERR, "error loading %s", mod_path); + D(("failed to load module - aborting")); + return PAM_ABORT; + } + } + } + + return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS ); +} + +/* Parse config file, allocate handler structures, dlopen() */ +int _pam_init_handlers(pam_handle_t *pamh) +{ + FILE *f; + int retval; + + D(("_pam_init_handlers called")); + IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR); + + /* Return immediately if everything is already loaded */ + if (pamh->handlers.handlers_loaded) { + return PAM_SUCCESS; + } + + D(("_pam_init_handlers: initializing")); + + /* First clean the service structure */ + + _pam_free_handlers(pamh); + if (! pamh->handlers.module) { + if ((pamh->handlers.module = + malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) { + _pam_system_log(LOG_CRIT, + "_pam_init_handlers: no memory loading module"); + return PAM_BUF_ERR; + } + pamh->handlers.modules_allocated = MODULE_CHUNK; + pamh->handlers.modules_used = 0; + } + + if (pamh->service_name == NULL) { + return PAM_BAD_ITEM; /* XXX - better error? */ + } + +#ifdef PAM_LOCKING + /* Is the PAM subsystem locked? */ + { + int fd_tmp; + + if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) { + _pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile (" + PAM_LOCK_FILE ") exists - aborting"); + (void) close(fd_tmp); + /* + * to avoid swamping the system with requests + */ + _pam_start_timer(pamh); + pam_fail_delay(pamh, 5000000); + _pam_await_timer(pamh, PAM_ABORT); + + return PAM_ABORT; + } + } +#endif /* PAM_LOCKING */ + + /* + * Now parse the config file(s) and add handlers + */ + { + struct stat test_d; + + /* Is there a PAM_CONFIG_D directory? */ + if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) { + char *filename; + int read_something=0; + + D(("searching " PAM_CONFIG_D " for config files")); + filename = malloc(sizeof(PAM_CONFIG_DF) + +strlen(pamh->service_name)); + if (filename == NULL) { + _pam_system_log(LOG_ERR, + "_pam_init_handlers: no memory; service %s", + pamh->service_name); + return PAM_BUF_ERR; + } + sprintf(filename, PAM_CONFIG_DF, pamh->service_name); + D(("opening %s", filename)); + f = fopen(filename, "r"); + if (f != NULL) { + /* would test magic here? */ + retval = _pam_parse_conf_file(pamh, f, pamh->service_name +#ifdef PAM_READ_BOTH_CONFS + , 0 +#endif /* PAM_READ_BOTH_CONFS */ + ); + fclose(f); + if (retval != PAM_SUCCESS) { + _pam_system_log(LOG_ERR, + "_pam_init_handlers: error reading %s", + filename); + _pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]", + pam_strerror(pamh, retval)); + } else { + read_something = 1; + } + } else { + D(("unable to open %s", filename)); +#ifdef PAM_READ_BOTH_CONFS + D(("checking %s", PAM_CONFIG)); + + if ((f = fopen(PAM_CONFIG,"r")) != NULL) { + retval = _pam_parse_conf_file(pamh, f, NULL, 1); + fclose(f); + } else +#endif /* PAM_READ_BOTH_CONFS */ + retval = PAM_SUCCESS; + /* + * XXX - should we log an error? Some people want to always + * use "other" + */ + } + _pam_drop(filename); + + if (retval == PAM_SUCCESS) { + /* now parse the PAM_DEFAULT_SERVICE_FILE */ + + D(("opening %s", PAM_DEFAULT_SERVICE_FILE)); + f = fopen(PAM_DEFAULT_SERVICE_FILE, "r"); + if (f != NULL) { + /* would test magic here? */ + retval = _pam_parse_conf_file(pamh, f + , PAM_DEFAULT_SERVICE +#ifdef PAM_READ_BOTH_CONFS + , 0 +#endif /* PAM_READ_BOTH_CONFS */ + ); + fclose(f); + if (retval != PAM_SUCCESS) { + _pam_system_log(LOG_ERR, + "_pam_init_handlers: error reading %s", + PAM_DEFAULT_SERVICE_FILE); + _pam_system_log(LOG_ERR, + "_pam_init_handlers: [%s]", + pam_strerror(pamh, retval)); + } else { + read_something = 1; + } + } else { + D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE)); + _pam_system_log(LOG_ERR, + "_pam_init_handlers: no default config %s", + PAM_DEFAULT_SERVICE_FILE); + } + if (!read_something) { /* nothing read successfully */ + retval = PAM_ABORT; + } + } + } else { + if ((f = fopen(PAM_CONFIG, "r")) == NULL) { + _pam_system_log(LOG_ERR, "_pam_init_handlers: could not open " + PAM_CONFIG ); + return PAM_ABORT; + } + + retval = _pam_parse_conf_file(pamh, f, NULL +#ifdef PAM_READ_BOTH_CONFS + , 0 +#endif /* PAM_READ_BOTH_CONFS */ + ); + + D(("closing configuration file")); + fclose(f); + } + } + + if (retval != PAM_SUCCESS) { + /* Read error */ + _pam_system_log(LOG_ERR, "error reading PAM configuration file"); + return PAM_ABORT; + } + + pamh->handlers.handlers_loaded = 1; + + D(("_pam_init_handlers exiting")); + return PAM_SUCCESS; +} + +/* + * This is where we read a line of the PAM config file. The line may be + * preceeded by lines of comments and also extended with "\\\n" + */ + +static int _pam_assemble_line(FILE *f, char *buffer, int buf_len) +{ + char *p = buffer; + char *s, *os; + int used = 0; + + /* loop broken with a 'break' when a non-'\\n' ended line is read */ + + D(("called.")); + for (;;) { + if (used >= buf_len) { + /* Overflow */ + D(("_pam_assemble_line: overflow")); + return -1; + } + if (fgets(p, buf_len - used, f) == NULL) { + if (used) { + /* Incomplete read */ + return -1; + } else { + /* EOF */ + return 0; + } + } + + /* skip leading spaces --- line may be blank */ + + s = p + strspn(p, " \n\t"); + if (*s && (*s != '#')) { + os = s; + + /* + * we are only interested in characters before the first '#' + * character + */ + + while (*s && *s != '#') + ++s; + if (*s == '#') { + *s = '\0'; + used += strlen(os); + break; /* the line has been read */ + } + + s = os; + + /* + * Check for backslash by scanning back from the end of + * the entered line, the '\n' has been included since + * normally a line is terminated with this + * character. fgets() should only return one though! + */ + + s += strlen(s); + while (s > os && ((*--s == ' ') || (*s == '\t') + || (*s == '\n'))); + + /* check if it ends with a backslash */ + if (*s == '\\') { + *s++ = ' '; /* replace backslash with ' ' */ + *s = '\0'; /* truncate the line here */ + used += strlen(os); + p = s; /* there is more ... */ + } else { + /* End of the line! */ + used += strlen(os); + break; /* this is the complete line */ + } + + } else { + /* Nothing in this line */ + /* Don't move p */ + } + } + + return used; +} + +typedef int (*servicefn)(pam_handle_t *, int, int, char **); + +int _pam_add_handler(pam_handle_t *pamh + , int must_fail, int other, int type + , int *actions, const char *mod_path + , int argc, char **argv, int argvlen) +{ + struct loaded_module *mod; + int x = 0; + struct handler **handler_p; + struct handler **handler_p2; + struct handlers *the_handlers; + const char *sym, *sym2; +#ifdef PAM_SHL + const char *_sym, *_sym2; +#endif + char *mod_full_path=NULL; + servicefn func, func2; + int success; + + D(("called.")); + IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR); + + /* if NULL set to something that can be searched for */ + switch (mod_path != NULL) { + default: + if (mod_path[0] == '/') { + break; + } + mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path)); + if (mod_full_path) { + sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path); + mod_path = mod_full_path; + break; + } + _pam_system_log(LOG_CRIT, "cannot malloc full mod path"); + case 0: + mod_path = UNKNOWN_MODULE_PATH; + } + + D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path)); + mod = pamh->handlers.module; + + /* First, ensure the module is loaded */ + while (x < pamh->handlers.modules_used) { + if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */ + break; + } + x++; + } + if (x == pamh->handlers.modules_used) { + /* Not found */ + if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) { + /* will need more memory */ + void *tmp = realloc(pamh->handlers.module, + (pamh->handlers.modules_allocated+MODULE_CHUNK) + *sizeof(struct loaded_module)); + if (tmp == NULL) { + D(("cannot enlarge module pointer memory")); + _pam_system_log(LOG_ERR, + "realloc returned NULL in _pam_add_handler"); + _pam_drop(mod_full_path); + return PAM_ABORT; + } + pamh->handlers.module = tmp; + pamh->handlers.modules_allocated += MODULE_CHUNK; + } + mod = &(pamh->handlers.module[x]); + /* Be pessimistic... */ + success = PAM_ABORT; + +#ifdef PAM_DYNAMIC + D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle)); + mod->dl_handle = +# ifdef PAM_SHL + shl_load(mod_path, BIND_IMMEDIATE, 0L); +# else /* PAM_SHL */ + dlopen(mod_path, RTLD_NOW); +# endif /* PAM_SHL */ + D(("_pam_add_handler: dlopen'ed")); + if (mod->dl_handle == NULL) { + D(("_pam_add_handler: dlopen(%s) failed", mod_path)); + _pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path); +# ifndef PAM_SHL + _pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror()); +# endif /* PAM_SHL */ + /* Don't abort yet; static code may be able to find function. + * But defaults to abort if nothing found below... */ + } else { + D(("module added successfully")); + success = PAM_SUCCESS; + mod->type = PAM_MT_DYNAMIC_MOD; + pamh->handlers.modules_used++; + } +#endif +#ifdef PAM_STATIC + /* Only load static function if function was not found dynamically. + * This code should work even if no dynamic loading is available. */ + if (success != PAM_SUCCESS) { + D(("_pam_add_handler: open static handler %s", mod_path)); + mod->dl_handle = _pam_open_static_handler(mod_path); + if (mod->dl_handle == NULL) { + D(("_pam_add_handler: unable to find static handler %s", + mod_path)); + _pam_system_log(LOG_ERR, + "unable to open static handler %s", mod_path); + /* Didn't find module in dynamic or static..will mark bad */ + } else { + D(("static module added successfully")); + success = PAM_SUCCESS; + mod->type = PAM_MT_STATIC_MOD; + pamh->handlers.modules_used++; + } + } +#endif + + if (success != PAM_SUCCESS) { /* add a malformed module */ + mod->dl_handle = NULL; + mod->type = PAM_MT_FAULTY_MOD; + pamh->handlers.modules_used++; + _pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path); + success = PAM_SUCCESS; /* We have successfully added a module */ + } + + /* indicate its name - later we will search for it by this */ + if ((mod->name = _pam_strdup(mod_path)) == NULL) { + D(("_pam_handler: couldn't get memory for mod_path")); + _pam_system_log(LOG_ERR, "no memory for module path", mod_path); + success = PAM_ABORT; + } + + } else { /* x != pamh->handlers.modules_used */ + mod += x; /* the located module */ + success = PAM_SUCCESS; + } + + _pam_drop(mod_full_path); + mod_path = NULL; /* no longer needed or trusted */ + + /* Now return error if necessary after trying all possible ways... */ + if (success != PAM_SUCCESS) + return(success); + + /* + * At this point 'mod' points to the stored/loaded module. If its + * dl_handle is unknown, then we must be able to indicate dispatch + * failure with 'must_fail' + */ + + /* Now define the handler(s) based on mod->dlhandle and type */ + + /* decide which list of handlers to use */ + the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf; + + handler_p = handler_p2 = NULL; + func = func2 = NULL; +#ifdef PAM_SHL + _sym2 = +#endif /* PAM_SHL */ + sym2 = NULL; + + /* point handler_p's at the root addresses of the function stacks */ + switch (type) { + case PAM_T_AUTH: + handler_p = &the_handlers->authenticate; + sym = SHLIB_SYM_PREFIX "pam_sm_authenticate"; + handler_p2 = &the_handlers->setcred; + sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred"; +#ifdef PAM_SHL + _sym = "_pam_sm_authenticate"; + _sym2 = "_pam_sm_setcred"; +#endif + break; + case PAM_T_SESS: + handler_p = &the_handlers->open_session; + sym = SHLIB_SYM_PREFIX "pam_sm_open_session"; + handler_p2 = &the_handlers->close_session; + sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session"; +#ifdef PAM_SHL + _sym = "_pam_sm_open_session"; + _sym2 = "_pam_sm_close_session"; +#endif + break; + case PAM_T_ACCT: + handler_p = &the_handlers->acct_mgmt; + sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt"; +#ifdef PAM_SHL + _sym = "_pam_sm_acct_mgmt"; +#endif + break; + case PAM_T_PASS: + handler_p = &the_handlers->chauthtok; + sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok"; +#ifdef PAM_SHL + _sym = "_pam_sm_chauthtok"; +#endif + break; + default: + /* Illegal module type */ + D(("_pam_add_handler: illegal module type %d", type)); + return PAM_ABORT; + } + + /* are the modules reliable? */ + if ( +#ifdef PAM_DYNAMIC + mod->type != PAM_MT_DYNAMIC_MOD + && +#endif /* PAM_DYNAMIC */ +#ifdef PAM_STATIC + mod->type != PAM_MT_STATIC_MOD + && +#endif /* PAM_STATIC */ + mod->type != PAM_MT_FAULTY_MOD + ) { + D(("_pam_add_handlers: illegal module library type; %d", mod->type)); + _pam_system_log(LOG_ERR, + "internal error: module library type not known: %s;%d", + sym, mod->type); + return PAM_ABORT; + } + + /* now identify this module's functions - for non-faulty modules */ + +#ifdef PAM_DYNAMIC + if ((mod->type == PAM_MT_DYNAMIC_MOD) && +# ifdef PAM_SHL + (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) && + shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func)) +# else /* PAM_SHL */ + (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL +# endif /* PAM_SHL */ + ) { + _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym); + } +#endif +#ifdef PAM_STATIC + if ((mod->type == PAM_MT_STATIC_MOD) && + (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) { + _pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym); + } +#endif + if (sym2) { +#ifdef PAM_DYNAMIC + if ((mod->type == PAM_MT_DYNAMIC_MOD) && +# ifdef PAM_SHL + (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&& + shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2)) +# else /* PAM_SHL */ + (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL +# endif /* PAM_SHL */ + ) { + _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2); + } +#endif +#ifdef PAM_STATIC + if ((mod->type == PAM_MT_STATIC_MOD) && + (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2)) + == NULL) { + _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2); + } +#endif + } + + /* here func (and perhaps func2) point to the appropriate functions */ + + /* add new handler to end of existing list */ + while (*handler_p != NULL) { + handler_p = &((*handler_p)->next); + } + + if ((*handler_p = malloc(sizeof(struct handler))) == NULL) { + _pam_system_log(LOG_CRIT, "cannot malloc struct handler #1"); + return (PAM_ABORT); + } + + (*handler_p)->must_fail = must_fail; /* failure forced? */ + (*handler_p)->func = func; + memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions)); + (*handler_p)->cached_retval = _PAM_INVALID_RETVAL; + (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval); + (*handler_p)->argc = argc; + (*handler_p)->argv = argv; /* not a copy */ + (*handler_p)->next = NULL; + + /* some of the modules have a second calling function */ + if (handler_p2) { + /* add new handler to end of existing list */ + while (*handler_p2) { + handler_p2 = &((*handler_p2)->next); + } + + if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) { + _pam_system_log(LOG_CRIT, "cannot malloc struct handler #2"); + return (PAM_ABORT); + } + + (*handler_p2)->must_fail = must_fail; /* failure forced? */ + (*handler_p2)->func = func2; + memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions)); + (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */ + /* Note, this next entry points to the handler_p value! */ + (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval); + (*handler_p2)->argc = argc; + if (argv) { + if (((*handler_p2)->argv = malloc(argvlen)) == NULL) { + _pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2"); + return (PAM_ABORT); + } + memcpy((*handler_p2)->argv, argv, argvlen); + } else { + (*handler_p2)->argv = NULL; /* no arguments */ + } + (*handler_p2)->next = NULL; + } + + D(("_pam_add_handler: returning successfully")); + + return PAM_SUCCESS; +} + +/* Free various allocated structures and dlclose() the libs */ +int _pam_free_handlers(pam_handle_t *pamh) +{ + struct loaded_module *mod; + + D(("called.")); + IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR); + + mod = pamh->handlers.module; + + /* Close all loaded modules */ + + while (pamh->handlers.modules_used) { + D(("_pam_free_handlers: dlclose(%s)", mod->name)); + free(mod->name); +#ifdef PAM_DYNAMIC + if (mod->type == PAM_MT_DYNAMIC_MOD) { +# ifdef PAM_SHL + shl_unload(mod->dl_handle); +# else + dlclose(mod->dl_handle); +# endif + } +#endif + mod++; + pamh->handlers.modules_used--; + } + + /* Free all the handlers */ + + _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate)); + _pam_free_handlers_aux(&(pamh->handlers.conf.setcred)); + _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt)); + _pam_free_handlers_aux(&(pamh->handlers.conf.open_session)); + _pam_free_handlers_aux(&(pamh->handlers.conf.close_session)); + _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok)); + + _pam_free_handlers_aux(&(pamh->handlers.other.authenticate)); + _pam_free_handlers_aux(&(pamh->handlers.other.setcred)); + _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt)); + _pam_free_handlers_aux(&(pamh->handlers.other.open_session)); + _pam_free_handlers_aux(&(pamh->handlers.other.close_session)); + _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok)); + + /* no more loaded modules */ + + _pam_drop(pamh->handlers.module); + + /* Indicate that handlers are not initialized for this pamh */ + + pamh->handlers.handlers_loaded = 0; + + return PAM_SUCCESS; +} + +void _pam_start_handlers(pam_handle_t *pamh) +{ + D(("called.")); + /* NB. There is no check for a NULL pamh here, since no return + * value to communicate the fact! */ + + /* Indicate that handlers are not initialized for this pamh */ + pamh->handlers.handlers_loaded = 0; + + pamh->handlers.modules_allocated = 0; + pamh->handlers.modules_used = 0; + pamh->handlers.module = NULL; + + /* initialize the .conf and .other entries */ + + pamh->handlers.conf.authenticate = NULL; + pamh->handlers.conf.setcred = NULL; + pamh->handlers.conf.acct_mgmt = NULL; + pamh->handlers.conf.open_session = NULL; + pamh->handlers.conf.close_session = NULL; + pamh->handlers.conf.chauthtok = NULL; + + pamh->handlers.other.authenticate = NULL; + pamh->handlers.other.setcred = NULL; + pamh->handlers.other.acct_mgmt = NULL; + pamh->handlers.other.open_session = NULL; + pamh->handlers.other.close_session = NULL; + pamh->handlers.other.chauthtok = NULL; +} + +void _pam_free_handlers_aux(struct handler **hp) +{ + struct handler *h = *hp; + struct handler *last; + + D(("called.")); + while (h) { + last = h; + _pam_drop(h->argv); /* This is all alocated in a single chunk */ + h = h->next; + memset(last, 0, sizeof(*last)); + free(last); + } + + *hp = NULL; +} diff --git a/Linux-PAM/libpam/pam_item.c b/Linux-PAM/libpam/pam_item.c new file mode 100644 index 00000000..3dcbf616 --- /dev/null +++ b/Linux-PAM/libpam/pam_item.c @@ -0,0 +1,333 @@ +/* pam_item.c */ + +/* + * $Id: pam_item.c,v 1.1.1.1 2001/04/29 04:17:06 hartmans Exp $ + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include "pam_private.h" + +#define RESET(X, Y) \ +{ \ + char *_TMP_ = (X); \ + if (_TMP_ != (Y)) { \ + (X) = (Y) ? _pam_strdup(Y) : NULL; \ + if (_TMP_) \ + free(_TMP_); \ + } \ +} + +/* handy version id */ + +unsigned int __libpam_version = LIBPAM_VERSION; + +/* functions */ + +int pam_set_item (pam_handle_t *pamh, int item_type, const void *item) +{ + int retval; + + D(("called")); + + IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR); + + retval = PAM_SUCCESS; + + switch (item_type) { + + case PAM_SERVICE: + /* Setting handlers_loaded to 0 will cause the handlers + * to be reloaded on the next call to a service module. + */ + pamh->handlers.handlers_loaded = 0; + RESET(pamh->service_name, item); + { + char *tmp; + for (tmp=pamh->service_name; *tmp; ++tmp) + *tmp = tolower(*tmp); /* require lower case */ + } + break; + + case PAM_USER: + RESET(pamh->user, item); + break; + + case PAM_USER_PROMPT: + RESET(pamh->prompt, item); + break; + + case PAM_TTY: + D(("setting tty to %s", item)); + RESET(pamh->tty, item); + break; + + case PAM_RUSER: + RESET(pamh->ruser, item); + break; + + case PAM_RHOST: + RESET(pamh->rhost, item); + break; + + case PAM_AUTHTOK: + /* + * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from + * modules. + */ + if (__PAM_FROM_MODULE(pamh)) { + char *_TMP_ = pamh->authtok; + if (_TMP_ == item) /* not changed so leave alone */ + break; + pamh->authtok = (item) ? _pam_strdup(item) : NULL; + if (_TMP_) { + _pam_overwrite(_TMP_); + free(_TMP_); + } + } else { + retval = PAM_BAD_ITEM; + } + + break; + + case PAM_OLDAUTHTOK: + /* + * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from + * modules. + */ + if (__PAM_FROM_MODULE(pamh)) { + char *_TMP_ = pamh->oldauthtok; + if (_TMP_ == item) /* not changed so leave alone */ + break; + pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL; + if (_TMP_) { + _pam_overwrite(_TMP_); + free(_TMP_); + } + } else { + retval = PAM_BAD_ITEM; + } + + break; + + case PAM_CONV: /* want to change the conversation function */ + if (item == NULL) { + _pam_system_log(LOG_ERR, + "pam_set_item: attempt to set conv() to NULL"); + retval = PAM_PERM_DENIED; + } else { + struct pam_conv *tconv; + + if ((tconv= + (struct pam_conv *) malloc(sizeof(struct pam_conv)) + ) == NULL) { + _pam_system_log(LOG_CRIT, + "pam_set_item: malloc failed for pam_conv"); + retval = PAM_BUF_ERR; + } else { + memcpy(tconv, item, sizeof(struct pam_conv)); + _pam_drop(pamh->pam_conversation); + pamh->pam_conversation = tconv; + } + } + break; + + case PAM_FAIL_DELAY: + pamh->fail_delay.delay_fn_ptr = item; + break; + + default: + retval = PAM_BAD_ITEM; + } + + return retval; +} + +int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item) +{ + int retval = PAM_SUCCESS; + + D(("called.")); + IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR); + + if (item == NULL) { + _pam_system_log(LOG_ERR, + "pam_get_item: nowhere to place requested item"); + return PAM_PERM_DENIED; + } + + switch (item_type) { + case PAM_SERVICE: + *item = pamh->service_name; + break; + + case PAM_USER: + D(("returning user=%s", pamh->user)); + *item = pamh->user; + break; + + case PAM_USER_PROMPT: + D(("returning userprompt=%s", pamh->user)); + *item = pamh->prompt; + break; + + case PAM_TTY: + D(("returning tty=%s", pamh->tty)); + *item = pamh->tty; + break; + + case PAM_RUSER: + *item = pamh->ruser; + break; + + case PAM_RHOST: + *item = pamh->rhost; + break; + + case PAM_AUTHTOK: + /* + * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from + * modules. + */ + if (__PAM_FROM_MODULE(pamh)) { + *item = pamh->authtok; + } else { + retval = PAM_BAD_ITEM; + } + break; + + case PAM_OLDAUTHTOK: + /* + * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from + * modules. + */ + if (__PAM_FROM_MODULE(pamh)) { + *item = pamh->oldauthtok; + } else { + retval = PAM_BAD_ITEM; + } + break; + + case PAM_CONV: + *item = pamh->pam_conversation; + break; + + case PAM_FAIL_DELAY: + *item = pamh->fail_delay.delay_fn_ptr; + break; + + default: + retval = PAM_BAD_ITEM; + } + + return retval; +} + +/* + * This function is the 'preferred method to obtain the username'. + */ + +int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) +{ + const char *use_prompt; + int retval; + struct pam_message msg,*pmsg; + struct pam_response *resp; + + D(("called.")); + IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR); + + if (pamh->pam_conversation == NULL) { + _pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh"); + return PAM_SERVICE_ERR; + } + + if (user == NULL) { /* ensure the the module has suplied a destination */ + _pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username"); + return PAM_PERM_DENIED; + } else + *user = NULL; + + if (pamh->user) { /* have one so return it */ + *user = pamh->user; + return PAM_SUCCESS; + } + + /* will need a prompt */ + use_prompt = prompt; + if (use_prompt == NULL) { + use_prompt = pamh->prompt; + if (use_prompt == NULL) { + use_prompt = PAM_DEFAULT_PROMPT; + } + } + + /* If we are resuming an old conversation, we verify that the prompt + is the same. Anything else is an error. */ + if (pamh->former.want_user) { + /* must have a prompt to resume with */ + if (! pamh->former.prompt) { + _pam_system_log(LOG_ERR, + "pam_get_user: failed to resume with prompt" + ); + return PAM_ABORT; + } + + /* must be the same prompt as last time */ + if (strcmp(pamh->former.prompt, use_prompt)) { + _pam_system_log(LOG_ERR, + "pam_get_user: resumed with different prompt"); + return PAM_ABORT; + } + + /* ok, we can resume where we left off last time */ + pamh->former.want_user = PAM_FALSE; + _pam_overwrite(pamh->former.prompt); + _pam_drop(pamh->former.prompt); + } + + /* converse with application -- prompt user for a username */ + pmsg = &msg; + msg.msg_style = PAM_PROMPT_ECHO_ON; + msg.msg = use_prompt; + resp = NULL; + + retval = pamh->pam_conversation-> + conv(1, (const struct pam_message **) &pmsg, &resp, + pamh->pam_conversation->appdata_ptr); + + if (retval == PAM_CONV_AGAIN) { + /* conversation function is waiting for an event - save state */ + D(("conversation function is not ready yet")); + pamh->former.want_user = PAM_TRUE; + pamh->former.prompt = _pam_strdup(use_prompt); + } else if (resp == NULL) { + /* + * conversation should have given a response + */ + D(("pam_get_user: no response provided")); + retval = PAM_CONV_ERR; + } else if (retval == PAM_SUCCESS) { /* copy the username */ + /* + * now we set the PAM_USER item -- this was missing from pre.53 + * releases. However, reading the Sun manual, it is part of + * the standard API. + */ + RESET(pamh->user, resp->resp); + *user = pamh->user; + } + + if (resp) { + /* + * note 'resp' is allocated by the application and is + * correctly free()'d here + */ + _pam_drop_reply(resp, 1); + } + + D(("completed")); + return retval; /* pass on any error from conversation */ +} diff --git a/Linux-PAM/libpam/pam_log.c b/Linux-PAM/libpam/pam_log.c new file mode 100644 index 00000000..2da1b280 --- /dev/null +++ b/Linux-PAM/libpam/pam_log.c @@ -0,0 +1,375 @@ +/* + * pam_log.c -- PAM system logging + * + * $Id: pam_log.c,v 1.1.1.1 2001/04/29 04:17:07 hartmans Exp $ + * + */ + +#include "pam_private.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#ifdef __hpux +# include <stdio.h> +# include <syslog.h> +# ifdef __STDC__ +# ifndef __P +# define __P(p) p +# endif /* __P */ +# include <stdarg.h> +# define VA_LOCAL_DECL va_list ap; +# define VA_START(f) va_start(ap, f) +# define VA_END va_end(ap) +# else /* __STDC__ */ +# ifndef __P +# define __P(p) () +# endif /* __P */ +# include <varargs.h> +# define VA_LOCAL_DECL va_list ap; +# define VA_START(f) va_start(ap) +# define VA_END va_end(ap) +# endif /* __STDC__ */ +/************************************************************** + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + **************************************************************/ + +static void dopr(); +static char *end; +# ifndef _SCO_DS +/* VARARGS3 */ +int +# ifdef __STDC__ +snprintf(char *str, size_t count, const char *fmt, ...) +# else /* __STDC__ */ +snprintf(str, count, fmt, va_alist) + char *str; + size_t count; + const char *fmt; + va_dcl +# endif /* __STDC__ */ +{ + int len; + VA_LOCAL_DECL + + VA_START(fmt); + len = vsnprintf(str, count, fmt, ap); + VA_END; + return len; +} +# endif /* _SCO_DS */ + +int +# ifdef __STDC__ +vsnprintf(char *str, size_t count, const char *fmt, va_list args) +# else /* __STDC__ */ +vsnprintf(str, count, fmt, args) + char *str; + int count; + char *fmt; + va_list args; +# endif /* __STDC__ */ +{ + str[0] = 0; + end = str + count - 1; + dopr( str, fmt, args ); + if (count > 0) + end[0] = 0; + return strlen(str); +} + +/* + * dopr(): poor man's version of doprintf + */ + +static void fmtstr __P((char *value, int ljust, int len, int zpad, + int maxwidth)); +static void fmtnum __P((long value, int base, int dosign, int ljust, int len, + int zpad)); +static void dostr __P(( char * , int )); +static char *output; +static void dopr_outch __P(( int c )); + +static void +# ifdef __STDC__ +dopr(char * buffer, const char * format, va_list args ) +# else /* __STDC__ */ +dopr( buffer, format, args ) + char *buffer; + char *format; + va_list args; +# endif /* __STDC__ */ +{ + int ch; + long value; + int longflag = 0; + int pointflag = 0; + int maxwidth = 0; + char *strvalue; + int ljust; + int len; + int zpad; + + output = buffer; + while( (ch = *format++) ){ + switch( ch ){ + case '%': + ljust = len = zpad = maxwidth = 0; + longflag = pointflag = 0; + nextch: + ch = *format++; + switch( ch ){ + case 0: + dostr( "**end of format**" , 0); + return; + case '-': ljust = 1; goto nextch; + case '0': /* set zero padding if len not set */ + if(len==0 && !pointflag) zpad = '0'; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + if (pointflag) + maxwidth = maxwidth*10 + ch - '0'; + else + len = len*10 + ch - '0'; + goto nextch; + case '*': + if (pointflag) + maxwidth = va_arg( args, int ); + else + len = va_arg( args, int ); + goto nextch; + case '.': pointflag = 1; goto nextch; + case 'l': longflag = 1; goto nextch; + case 'u': case 'U': + /*fmtnum(value,base,dosign,ljust,len,zpad) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,0, ljust, len, zpad ); break; + case 'o': case 'O': + /*fmtnum(value,base,dosign,ljust,len,zpad) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 8,0, ljust, len, zpad ); break; + case 'd': case 'D': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,1, ljust, len, zpad ); break; + case 'x': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 16,0, ljust, len, zpad ); break; + case 'X': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value,-16,0, ljust, len, zpad ); break; + case 's': + strvalue = va_arg( args, char *); + if (maxwidth > 0 || !pointflag) { + if (pointflag && len > maxwidth) + len = maxwidth; /* Adjust padding */ + fmtstr( strvalue,ljust,len,zpad, maxwidth); + } + break; + case 'c': + ch = va_arg( args, int ); + dopr_outch( ch ); break; + case '%': dopr_outch( ch ); continue; + default: + dostr( "???????" , 0); + } + break; + default: + dopr_outch( ch ); + break; + } + } + *output = 0; +} + +static void +fmtstr( value, ljust, len, zpad, maxwidth ) + char *value; + int ljust, len, zpad, maxwidth; +{ + int padlen, strlen; /* amount to pad */ + + if( value == 0 ){ + value = "<NULL>"; + } + for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */ + if (strlen > maxwidth && maxwidth) + strlen = maxwidth; + padlen = len - strlen; + if( padlen < 0 ) padlen = 0; + if( ljust ) padlen = -padlen; + while( padlen > 0 ) { + dopr_outch( ' ' ); + --padlen; + } + dostr( value, maxwidth ); + while( padlen < 0 ) { + dopr_outch( ' ' ); + ++padlen; + } +} + +static void +fmtnum( value, base, dosign, ljust, len, zpad ) + long value; + int base, dosign, ljust, len, zpad; +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int padlen = 0; /* amount to pad */ + int caps = 0; + + /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", + value, base, dosign, ljust, len, zpad )); */ + uvalue = value; + if( dosign ){ + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } + } + if( base < 0 ){ + caps = 1; + base = -base; + } + do{ + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + }while(uvalue); + convert[place] = 0; + padlen = len - place; + if( padlen < 0 ) padlen = 0; + if( ljust ) padlen = -padlen; + /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", + convert,place,signvalue,padlen)); */ + if( zpad && padlen > 0 ){ + if( signvalue ){ + dopr_outch( signvalue ); + --padlen; + signvalue = 0; + } + while( padlen > 0 ){ + dopr_outch( zpad ); + --padlen; + } + } + while( padlen > 0 ) { + dopr_outch( ' ' ); + --padlen; + } + if( signvalue ) dopr_outch( signvalue ); + while( place > 0 ) dopr_outch( convert[--place] ); + while( padlen < 0 ){ + dopr_outch( ' ' ); + ++padlen; + } +} + +static void +dostr( str , cut) + char *str; + int cut; +{ + if (cut) { + while(*str && cut-- > 0) dopr_outch(*str++); + } else { + while(*str) dopr_outch(*str++); + } +} + +static void +dopr_outch( c ) + int c; +{ + if( end == 0 || output < end ) + *output++ = c; +} + +int +# ifdef __STDC__ +vsyslog(int priority, const char *fmt, ...) +# else /* __STDC__ */ +vsyslog(priority, fmt, va_alist) + int priority; + const char *fmt; + va_dcl +# endif /* __STDC__ */ +{ + VA_LOCAL_DECL + char logbuf[BUFSIZ]; + + VA_START(fmt); + + vsnprintf(logbuf, BUFSIZ, fmt, ap); + syslog(priority, "%s", logbuf); + + VA_END; +} +#endif /* __hpux */ + +/* internal logging function */ + +void _pam_system_log(int priority, const char *format, ... ) +{ + va_list args; + char *eformat; + + D(("pam_system_log called")); + + if (format == NULL) { + D(("NULL format to _pam_system_log() call")); + return; + } + + va_start(args, format); + + eformat = malloc(sizeof(_PAM_SYSTEM_LOG_PREFIX)+strlen(format)); + if (eformat != NULL) { + strcpy(eformat, _PAM_SYSTEM_LOG_PREFIX); + strcpy(eformat + sizeof(_PAM_SYSTEM_LOG_PREFIX) - 1, format); + vsyslog(priority, eformat, args); + _pam_overwrite(eformat); + _pam_drop(eformat); + } else { + vsyslog(priority, format, args); + } + + va_end(args); + + D(("done.")); +} + diff --git a/Linux-PAM/libpam/pam_malloc.c b/Linux-PAM/libpam/pam_malloc.c new file mode 100644 index 00000000..7cc177c6 --- /dev/null +++ b/Linux-PAM/libpam/pam_malloc.c @@ -0,0 +1,418 @@ +/* + * $Id: pam_malloc.c,v 1.1.1.2 2002/09/15 20:08:37 hartmans Exp $ + */ + +/* + * This pair of files helps to locate memory leaks. It is a wrapper for + * the malloc family of calls. (Actutally, it currently only deals + * with calloc, malloc, realloc, free, strdup and exit) + * + * To use these functions the header "pam_malloc.h" must be included + * in all parts of the code (that use the malloc functions) and this + * file must be linked with the result. The pam_malloc_flags can be + * set from another function and determine the level of logging. + * + * The output is via the macros defined in _pam_macros.h + * + * It is a debugging tool and should be turned off in released code. + * + * This suite was written by Andrew Morgan <morgan@kernel.org> for + * Linux-PAM. + */ + +#ifndef DEBUG +#define DEBUG +#endif +#include "pam_private.h" + +#include <security/pam_malloc.h> +#include <security/_pam_macros.h> + +/* this must be done to stop infinite recursion! */ +#undef malloc +#undef calloc +#undef free +#undef realloc +#undef exit +#undef strdup + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* + * default debugging level + */ + +int pam_malloc_flags = PAM_MALLOC_ALL; +int pam_malloc_delay_length = 4; + +#define on(x) ((pam_malloc_flags&(x))==(x)) + +/* + * the implementation + */ + +static const char *last_fn=NULL; +static const char *last_file=NULL; +static const char *last_call=NULL; +static int last_line = 1; + +#define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; } + +static void set_last_(const char *x, const char *f + , const char *fn, const int l) +{ + last_fn = x ? x : "error-in-pam_malloc.."; + last_file = f ? f : "*bad-file*"; + last_call = fn ? fn: "*bad-fn*"; + last_line = l; +} + +static void _pam_output_xdebug_info(void) +{ + FILE *logfile; + int must_close = 1, fd; + +#ifdef O_NOFOLLOW + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { +#else + if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { +#endif + if (!(logfile = fdopen(fd,"a"))) { + logfile = stderr; + must_close = 0; + close(fd); + } + } else { + logfile = stderr; + must_close = 0; + } + fprintf(logfile, "[%s:%s(%d)->%s()] ", + last_file, last_call, last_line, last_fn); + fflush(logfile); + if (must_close) + fclose(logfile); +} + +static void hinder(void) +{ + if (on(PAM_MALLOC_PAUSE)) { + if (on(0)) err(("pause requested")); + sleep(pam_malloc_delay_length); + } + + if (on(PAM_MALLOC_STOP)) { + if (on(0)) err(("stop requested")); + exit(1); + } +} + +/* + * here are the memory pointer registering functions.. these actually + * use malloc(!) but that's ok! ;^) + */ + +struct reference { + void *ptr; /* pointer */ + int nelements; /* number of elements */ + int size; /* - each of this size */ + char *file; /* where it was requested - filename */ + char *function; /* - function */ + int line; /* - line number */ +/* + * linking info + */ + struct reference *next; +}; + +static void _dump(const char *say, const struct reference *ref) +{ + _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>" + , say + , ref->ptr,ref->nelements,ref->size + , ref->function,ref->file,ref->line); +} + +static struct reference *root=NULL; + +static char *_strdup(const char *x) +{ + char *s; + + s = (char *)malloc(strlen(x)+1); + if (s == NULL) { + if (on(0)) err(("_strdup failed")); + exit(1); + } + + strcpy(s,x); + return s; +} + +static void add_new_ref(void *new, int n, int size) +{ + struct reference *ref=NULL; + + ref = (struct reference *) malloc( sizeof(struct reference) ); + if (new == NULL || ref == NULL) { + if (on(0)) err(("internal error {add_new_ref}")); + exit(1); + } + + ref->ptr = new; + ref->nelements = n; + ref->size = size; + + ref->file = _strdup(last_file); + ref->function = _strdup(last_call); + ref->line = last_line; + + ref->next = root; + + if (on(PAM_MALLOC_REQUEST)) { + _dump("new_ptr", ref); + } + + root = ref; +} + +static void del_old_ref(void *old) +{ + struct reference *this,*last; + + if (old == NULL) { + if (on(0)) err(("internal error {del_old_ref}")); + exit(1); + } + + /* locate old pointer */ + + last = NULL; + this = root; + while (this) { + if (this->ptr == old) + break; + last = this; + this = this->next; + } + + /* Did we find a reference ? */ + + if (this) { + if (on(PAM_MALLOC_FREE)) { + _dump("free old_ptr", this); + } + if (last == NULL) { + root = this->next; + } else { + last->next = this->next; + } + free(this->file); + free(this->function); + free(this); + } else { + if (on(0)) err(("ERROR!: bad memory")); + hinder(); + } +} + +static void verify_old_ref(void *old) +{ + struct reference *this; + + if (old == NULL) { + if (on(0)) err(("internal error {verify_old_ref}")); + exit(1); + } + + /* locate old pointer */ + + this = root; + while (this) { + if (this->ptr == old) + break; + this = this->next; + } + + /* Did we find a reference ? */ + + if (this) { + if (on(PAM_MALLOC_VERIFY)) { + _dump("verify_ptr", this); + } + } else { + if (on(0)) err(("ERROR!: bad request")); + hinder(); + } +} + +static void dump_memory_list(const char *dump) +{ + struct reference *this; + + this = root; + if (this) { + if (on(0)) err(("un-free()'d memory")); + while (this) { + _dump(dump, this); + this = this->next; + } + } else { + if (on(0)) err(("no memory allocated")); + } +} + +/* now for the wrappers */ + +#define _fn(x) set_last_(x,file,fn,line) + +void *pam_malloc(size_t size, const char *file, const char *fn, const int line) +{ + void *new; + + _fn("malloc"); + + if (on(PAM_MALLOC_FUNC)) err(("request for %d", size)); + + new = malloc(size); + if (new == NULL) { + if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); + } else { + if (on(PAM_MALLOC_REQUEST)) err(("request new")); + add_new_ref(new, 1, size); + } + + return new; +} + +void *pam_calloc(size_t nelm, size_t size + , const char *file, const char *fn, const int line) +{ + void *new; + + _fn("calloc"); + + if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size)); + + new = calloc(nelm,size); + if (new == NULL) { + if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); + } else { + if (on(PAM_MALLOC_REQUEST)) err(("request new")); + add_new_ref(new, nelm, size); + } + + return new; +} + +void pam_free(void *ptr + , const char *file, const char *fn, const int line) +{ + _fn("free"); + + if (on(PAM_MALLOC_FUNC)) + err(("request (%s:%s():%d) to free %p", file, fn, line, ptr)); + + if (ptr == NULL) { + if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer")); + } else { + if (on(PAM_MALLOC_FREE)) err(("deleted old")); + del_old_ref(ptr); + free(ptr); + } +} + +void *pam_memalign(size_t ali, size_t size + , const char *file, const char *fn, const int line) +{ + _fn("memalign"); + if (on(0)) err(("not implemented currently (Sorry)")); + exit(1); +} + +void *pam_realloc(void *ptr, size_t size + , const char *file, const char *fn, const int line) +{ + void *new; + + _fn("realloc"); + + if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size)); + + if (ptr == NULL) { + if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer")); + } else { + verify_old_ref(ptr); + } + + new = realloc(ptr, size); + if (new == NULL) { + if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); + } else { + if (ptr) { + if (on(PAM_MALLOC_FREE)) err(("deleted old")); + del_old_ref(ptr); + } else { + if (on(PAM_MALLOC_NULL)) err(("old is NULL")); + } + if (on(PAM_MALLOC_REQUEST)) err(("request new")); + add_new_ref(new, 1, size); + } + + return new; +} + +void *pam_valloc(size_t size + , const char *file, const char *fn, const int line) +{ + _fn("valloc"); + if (on(0)) err(("not implemented currently (Sorry)")); + exit(1); +} + +#include <alloca.h> + +void *pam_alloca(size_t size + , const char *file, const char *fn, const int line) +{ + _fn("alloca"); + if (on(0)) err(("not implemented currently (Sorry)")); + exit(1); +} + +void pam_exit(int i + , const char *file, const char *fn, const int line) +{ + D(("time to exit")); + + _fn("exit"); + + if (on(0)) err(("passed (%d)", i)); + if (on(PAM_MALLOC_LEAKED)) { + dump_memory_list("leaked"); + } + exit(i); +} + +char *pam_strdup(const char *orig, + const char *file, const char *fn, const int line) +{ + char *new; + + _fn("strdup"); + + if (on(PAM_MALLOC_FUNC)) err(("request for dup of [%s]", orig)); + + new = strdup(orig); + if (new == NULL) { + if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); + } else { + if (on(PAM_MALLOC_REQUEST)) err(("request dup of [%s]", orig)); + add_new_ref(new, 1, strlen(new)+1); + } + + return new; +} + +/* end of file */ diff --git a/Linux-PAM/libpam/pam_map.c b/Linux-PAM/libpam/pam_map.c new file mode 100644 index 00000000..c4af41a9 --- /dev/null +++ b/Linux-PAM/libpam/pam_map.c @@ -0,0 +1,78 @@ +/* pam_map.c - PAM mapping interface + * + * $Id: pam_map.c,v 1.1.1.1 2001/04/29 04:17:08 hartmans Exp $ + * + * This is based on the X/Open XSSO specification of March 1997. + * It is not implemented as it is going to change... after 1997/9/25. + * + */ + +#include <stdio.h> + +#include "pam_private.h" + +/* p 54 */ + +int pam_get_mapped_authtok(pam_handle_t *pamh, + const char *target_module_username, + const char *target_module_type, + const char *target_authn_domain, + size_t *target_authtok_len + unsigned char **target_module_authtok); +{ + D(("called")); + + IF_NO_PAMH("pam_get_mapped_authtok",pamh,PAM_SYSTEM_ERR); + + return PAM_SYSTEM_ERROR; +} + +/* p 68 */ + +int pam_set_mapped_authtok(pam_handle_t *pamh, + char *target_module_username, + size_t *target_authtok_len, + unsigned char *target_module_authtok, + char *target_module_type, + char *target_authn_domain) +{ + D(("called")); + + IF_NO_PAMH("pam_set_mapped_authtok",pamh,PAM_SYSTEM_ERR); + + return PAM_SYSTEM_ERROR; +} + +/* p 56 */ + +int pam_get_mapped_username(pam_handle_t *pamh, + const char *src_username, + const char *src_module_type, + const char *src_authn_domain, + const char *target_module_type, + const char *target_authn_domain, + char **target_module_username) +{ + D(("called")); + + IF_NO_PAMH("pam_get_mapped_username",pamh,PAM_SYSTEM_ERR); + + return PAM_SYSTEM_ERROR; +} + +/* p 70 */ + +int pam_set_mapped_username(pam_handle_t *pamh, + char *src_username, + char *src_module_type, + char *src_authn_domain, + char *target_module_username, + char *target_module_type, + char *target_authn_domain) +{ + D(("called")); + + IF_NO_PAMH("pam_set_mapped_username",pamh,PAM_SYSTEM_ERR); + + return PAM_SYSTEM_ERROR; +} diff --git a/Linux-PAM/libpam/pam_misc.c b/Linux-PAM/libpam/pam_misc.c new file mode 100644 index 00000000..53bd54de --- /dev/null +++ b/Linux-PAM/libpam/pam_misc.c @@ -0,0 +1,321 @@ +/* pam_misc.c -- This is random stuff */ + +/* + * $Id: pam_misc.c,v 1.1.1.2 2002/09/15 20:08:38 hartmans Exp $ + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <ctype.h> + +#include "pam_private.h" + +/* caseless string comparison: POSIX does not define this.. */ +int _pam_strCMP(const char *s, const char *t) +{ + int cf; + + do { + cf = tolower(*s) - tolower(*t); + ++t; + } while (!cf && *s++); + + return cf; +} + +char *_pam_StrTok(char *from, const char *format, char **next) +/* + * this function is a variant of the standard strtok, it differs in that + * it takes an additional argument and doesn't nul terminate tokens until + * they are actually reached. + */ +{ + char table[256], *end; + int i; + + if (from == NULL && (from = *next) == NULL) + return from; + + /* initialize table */ + for (i=1; i<256; table[i++] = '\0'); + for (i=0; format[i] ; table[(int)format[i++]] = 'y'); + + /* look for first non-format char */ + while (*from && table[(int)*from]) { + ++from; + } + + if (*from == '[') { + /* + * special case, "[...]" is considered to be a single + * object. Note, however, if one of the format[] chars is + * '[' this single string will not be read correctly. + * Note, any '[' inside the outer "[...]" pair will survive. + * Note, the first ']' will terminate this string, but + * that "\]" will get compressed into "]". That is: + * + * "[..[..\]..]..." --> "..[..].." + */ + char *to; + for (to=end=++from; *end && *end != ']'; ++to, ++end) { + if (*end == '\\' && end[1] == ']') + ++end; + if (to != end) { + *to = *end; + } + } + if (to != end) { + *to = '\0'; + } + /* note, this string is stripped of its edges: "..." is what + remains */ + } else if (*from) { + /* simply look for next blank char */ + for (end=from; *end && !table[(int)*end]; ++end); + } else { + return (*next = NULL); /* no tokens left */ + } + + /* now terminate what we have */ + if (*end) + *end++ = '\0'; + + /* indicate what it left */ + if (*end) { + *next = end; + } else { + *next = NULL; /* have found last token */ + } + + /* return what we have */ + return from; +} + +/* + * Safe duplication of character strings. "Paranoid"; don't leave + * evidence of old token around for later stack analysis. + */ + +char *_pam_strdup(const char *x) +{ + register char *new=NULL; + + if (x != NULL) { + register int i; + + for (i=0; x[i]; ++i); /* length of string */ + if ((new = malloc(++i)) == NULL) { + i = 0; + _pam_system_log(LOG_CRIT, "_pam_strdup: failed to get memory"); + } else { + while (i-- > 0) { + new[i] = x[i]; + } + } + x = NULL; + } + + return new; /* return the duplicate or NULL on error */ +} + +/* Generate argv, argc from s */ +/* caller must free(argv) */ + +int _pam_mkargv(char *s, char ***argv, int *argc) +{ + int l; + int argvlen = 0; + char *sbuf, *sbuf_start; + char **our_argv = NULL; + char **argvbuf; + char *argvbufp; +#ifdef DEBUG + int count=0; +#endif + + D(("_pam_mkargv called: %s",s)); + + *argc = 0; + + l = strlen(s); + if (l) { + if ((sbuf = sbuf_start = _pam_strdup(s)) == NULL) { + _pam_system_log(LOG_CRIT, + "pam_mkargv: null returned by _pam_strdup"); + D(("arg NULL")); + } else { + /* Overkill on the malloc, but not large */ + argvlen = (l + 1) * ((sizeof(char)) + sizeof(char *)); + if ((our_argv = argvbuf = malloc(argvlen)) == NULL) { + _pam_system_log(LOG_CRIT, + "pam_mkargv: null returned by malloc"); + } else { + char *tmp=NULL; + + argvbufp = (char *) argvbuf + (l * sizeof(char *)); + D(("[%s]",sbuf)); + while ((sbuf = _pam_StrTok(sbuf, " \n\t", &tmp))) { + D(("arg #%d",++count)); + D(("->[%s]",sbuf)); + strcpy(argvbufp, sbuf); + D(("copied token")); + *argvbuf = argvbufp; + argvbufp += strlen(argvbufp) + 1; + D(("stepped in argvbufp")); + (*argc)++; + argvbuf++; + sbuf = NULL; + D(("loop again?")); + } + _pam_drop(sbuf_start); + } + } + } + + *argv = our_argv; + + D(("_pam_mkargv returned")); + + return(argvlen); +} + +/* + * this function is used to protect the modules from accidental or + * semi-mallicious harm that an application may do to confuse the API. + */ + +void _pam_sanitize(pam_handle_t *pamh) +{ + int old_caller_is = pamh->caller_is; + + /* + * this is for security. We reset the auth-tokens here. + */ + __PAM_TO_MODULE(pamh); + pam_set_item(pamh, PAM_AUTHTOK, NULL); + pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); + pamh->caller_is = old_caller_is; +} + +/* + * This function scans the array and replaces the _PAM_ACTION_UNDEF + * entries with the default action. + */ + +void _pam_set_default_control(int *control_array, int default_action) +{ + int i; + + for (i=0; i<_PAM_RETURN_VALUES; ++i) { + if (control_array[i] == _PAM_ACTION_UNDEF) { + control_array[i] = default_action; + } + } +} + +/* + * This function is used to parse a control string. This string is a + * series of tokens of the following form: + * + * "[ ]*return_code[ ]*=[ ]*action/[ ]". + */ + +#include "pam_tokens.h" + +void _pam_parse_control(int *control_array, char *tok) +{ + const char *error; + int ret; + + while (*tok) { + int act, len; + + /* skip leading space */ + while (isspace((int)*tok) && *++tok); + if (!*tok) + break; + + /* identify return code */ + for (ret=0; ret<=_PAM_RETURN_VALUES; ++ret) { + len = strlen(_pam_token_returns[ret]); + if (!strncmp(_pam_token_returns[ret], tok, len)) { + break; + } + } + if (ret > _PAM_RETURN_VALUES || !*(tok += len)) { + error = "expecting return value"; + goto parse_error; + } + + /* observe '=' */ + while (isspace((int)*tok) && *++tok); + if (!*tok || *tok++ != '=') { + error = "expecting '='"; + goto parse_error; + } + + /* skip leading space */ + while (isspace((int)*tok) && *++tok); + if (!*tok) { + error = "expecting action"; + goto parse_error; + } + + /* observe action type */ + for (act=0; act < (-(_PAM_ACTION_UNDEF)); ++act) { + len = strlen(_pam_token_actions[act]); + if (!strncmp(_pam_token_actions[act], tok, len)) { + act *= -1; + tok += len; + break; + } + } + if (act > 0) { + /* + * Either we have a number or we have hit an error. In + * principle, there is nothing to stop us accepting + * negative offsets. (Although we would have to think of + * another way of encoding the tokens.) However, I really + * think this would be both hard to administer and easily + * cause looping problems. So, for now, we will just + * allow forward jumps. (AGM 1998/1/7) + */ + if (!isdigit((int)*tok)) { + error = "expecting jump number"; + goto parse_error; + } + /* parse a number */ + act = 0; + do { + act *= 10; + act += *tok - '0'; /* XXX - this assumes ascii behavior */ + } while (*++tok && isdigit((int)*tok)); + if (! act) { + /* we do not allow 0 jumps. There is a token ('ignore') + for that */ + error = "expecting non-zero"; + goto parse_error; + } + } + + /* set control_array element */ + if (ret != _PAM_RETURN_VALUES) { + control_array[ret] = act; + } else { + /* set the default to 'act' */ + _pam_set_default_control(control_array, act); + } + } + + /* that was a success */ + return; + +parse_error: + /* treat everything as bad */ + _pam_system_log(LOG_ERR, "pam_parse: %s; [...%s]", error, tok); + for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD); + +} diff --git a/Linux-PAM/libpam/pam_password.c b/Linux-PAM/libpam/pam_password.c new file mode 100644 index 00000000..756d8536 --- /dev/null +++ b/Linux-PAM/libpam/pam_password.c @@ -0,0 +1,57 @@ +/* pam_password.c - PAM Password Management */ + +/* + * $Id: pam_password.c,v 1.1.1.1 2001/04/29 04:17:08 hartmans Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> + +/* #define DEBUG */ + +#include "pam_private.h" + +int pam_chauthtok(pam_handle_t *pamh, int flags) +{ + int retval; + + D(("called.")); + + IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + if (pamh->former.choice == PAM_NOT_STACKED) { + _pam_start_timer(pamh); /* we try to make the time for a failure + independent of the time it takes to + fail */ + _pam_sanitize(pamh); + pamh->former.update = PAM_FALSE; + } + + /* first call to check if there will be a problem */ + if (pamh->former.update || + (retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK, + PAM_CHAUTHTOK)) == PAM_SUCCESS) { + D(("completed check ok: former=%d", pamh->former.update)); + pamh->former.update = PAM_TRUE; + retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK, + PAM_CHAUTHTOK); + } + + /* if we completed we should clean up */ + if (retval != PAM_INCOMPLETE) { + _pam_sanitize(pamh); + pamh->former.update = PAM_FALSE; + _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ + D(("pam_chauthtok exit %d - %d", retval, pamh->former.choice)); + } else { + D(("will resume when ready", retval)); + } + + return retval; +} + diff --git a/Linux-PAM/libpam/pam_private.h b/Linux-PAM/libpam/pam_private.h new file mode 100644 index 00000000..7b4c7490 --- /dev/null +++ b/Linux-PAM/libpam/pam_private.h @@ -0,0 +1,328 @@ +/* + * pam_private.h + * + * $Id: pam_private.h,v 1.1.1.2 2002/09/15 20:08:39 hartmans Exp $ + * + * This is the Linux-PAM Library Private Header. It contains things + * internal to the Linux-PAM library. Things not needed by either an + * application or module. + * + * Please see end of file for copyright. + * + * Creator: Marc Ewing. + * Maintained: CVS + */ + +#ifndef _PAM_PRIVATE_H +#define _PAM_PRIVATE_H + +#include <security/_pam_aconf.h> + +/* this is not used at the moment --- AGM */ +#define LIBPAM_VERSION (LIBPAM_VERSION_MAJOR*0x100 + LIBPAM_VERSION_MINOR) + +#include <security/pam_appl.h> +#include <security/pam_modules.h> + +/* the Linux-PAM configuration file */ + +#define PAM_CONFIG "/etc/pam.conf" +#define PAM_CONFIG_D "/etc/pam.d" +#define PAM_CONFIG_DF "/etc/pam.d/%s" + +#define PAM_DEFAULT_SERVICE "other" /* lower case */ +#define PAM_DEFAULT_SERVICE_FILE PAM_CONFIG_D "/" PAM_DEFAULT_SERVICE + +#ifdef PAM_LOCKING +/* + * the Linux-PAM lock file. If it exists Linux-PAM will abort. Use it + * to block access to libpam + */ +#define PAM_LOCK_FILE "/var/lock/subsys/PAM" +#endif + +/* components of the pam_handle structure */ + +#define _PAM_INVALID_RETVAL -1 /* default value for cached_retval */ + +struct handler { + int must_fail; + int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv); + int actions[_PAM_RETURN_VALUES]; + /* set by authenticate, open_session, chauthtok(1st) + consumed by setcred, close_session, chauthtok(2nd) */ + int cached_retval; int *cached_retval_p; + int argc; + char **argv; + struct handler *next; +}; + +struct loaded_module { + char *name; + int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */ + void *dl_handle; +}; + +#define PAM_MT_DYNAMIC_MOD 0 +#define PAM_MT_STATIC_MOD 1 +#define PAM_MT_FAULTY_MOD 2 + +struct handlers { + struct handler *authenticate; + struct handler *setcred; + struct handler *acct_mgmt; + struct handler *open_session; + struct handler *close_session; + struct handler *chauthtok; +}; + +struct service { + struct loaded_module *module; /* Only used for dynamic loading */ + int modules_allocated; + int modules_used; + int handlers_loaded; + + struct handlers conf; /* the configured handlers */ + struct handlers other; /* the default handlers */ +}; + +/* + * Environment helper functions + */ + +#define PAM_ENV_CHUNK 10 /* chunks of memory calloc()'d * + * at once */ + +struct pam_environ { + int entries; /* the number of pointers available */ + int requested; /* the number of pointers used: * + * 1 <= requested <= entries */ + char **list; /* the environment storage (a list * + * of pointers to malloc() memory) */ +}; + +#include <sys/time.h> + +typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean; + +struct _pam_fail_delay { + _pam_boolean set; + unsigned int delay; + time_t begin; + const void *delay_fn_ptr; +}; + +struct _pam_former_state { +/* this is known and set by _pam_dispatch() */ + int choice; /* which flavor of module function did we call? */ + +/* state info for the _pam_dispatch_aux() function */ + int depth; /* how deep in the stack were we? */ + int impression; /* the impression at that time */ + int status; /* the status before returning incomplete */ + +/* state info used by pam_get_user() function */ + int want_user; + char *prompt; /* saved prompt information */ + +/* state info for the pam_chauthtok() function */ + _pam_boolean update; +}; + +struct pam_handle { + char *authtok; + unsigned caller_is; + struct pam_conv *pam_conversation; + char *oldauthtok; + char *prompt; /* for use by pam_get_user() */ + char *service_name; + char *user; + char *rhost; + char *ruser; + char *tty; + struct pam_data *data; + struct pam_environ *env; /* structure to maintain environment list */ + struct _pam_fail_delay fail_delay; /* helper function for easy delays */ + struct service handlers; + struct _pam_former_state former; /* library state - support for + event driven applications */ +}; + +/* Values for select arg to _pam_dispatch() */ +#define PAM_NOT_STACKED 0 +#define PAM_AUTHENTICATE 1 +#define PAM_SETCRED 2 +#define PAM_ACCOUNT 3 +#define PAM_OPEN_SESSION 4 +#define PAM_CLOSE_SESSION 5 +#define PAM_CHAUTHTOK 6 + +#define _PAM_ACTION_IS_JUMP(x) ((x) > 0) +#define _PAM_ACTION_IGNORE 0 +#define _PAM_ACTION_OK -1 +#define _PAM_ACTION_DONE -2 +#define _PAM_ACTION_BAD -3 +#define _PAM_ACTION_DIE -4 +#define _PAM_ACTION_RESET -5 +/* Add any new entries here. Will need to change ..._UNDEF and then + * need to change pam_tokens.h */ +#define _PAM_ACTION_UNDEF -6 /* this is treated as an error + ( = _PAM_ACTION_BAD) */ + +/* character tables for parsing config files */ +extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF]; +extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1]; + +/* + * internally defined functions --- these should not be directly + * called by applications or modules + */ +int _pam_dispatch(pam_handle_t *pamh, int flags, int choice); + +/* Free various allocated structures and dlclose() the libs */ +int _pam_free_handlers(pam_handle_t *pamh); + +/* Parse config file, allocate handler structures, dlopen() */ +int _pam_init_handlers(pam_handle_t *pamh); + +/* Set all hander stuff to 0/NULL - called once from pam_start() */ +void _pam_start_handlers(pam_handle_t *pamh); + +/* environment helper functions */ + +/* create the environment structure */ +int _pam_make_env(pam_handle_t *pamh); + +/* delete the environment structure */ +void _pam_drop_env(pam_handle_t *pamh); + +/* these functions deal with failure delays as required by the + authentication modules and application. Their *interface* is likely + to remain the same although their function is hopefully going to + improve */ + +/* reset the timer to no-delay */ +void _pam_reset_timer(pam_handle_t *pamh); + +/* this sets the clock ticking */ +void _pam_start_timer(pam_handle_t *pamh); + +/* this waits for the clock to stop ticking if status != PAM_SUCCESS */ +void _pam_await_timer(pam_handle_t *pamh, int status); + +typedef void (*voidfunc(void))(void); +#ifdef PAM_STATIC + +/* The next two in ../modules/_pam_static/pam_static.c */ + +/* Return pointer to data structure used to define a static module */ +struct pam_module * _pam_open_static_handler(const char *path); + +/* Return pointer to function requested from static module */ + +voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname); + +#endif + +/* For now we just use a stack and linear search for module data. */ +/* If it becomes apparent that there is a lot of data, it should */ +/* changed to either a sorted list or a hash table. */ + +struct pam_data { + char *name; + void *data; + void (*cleanup)(pam_handle_t *pamh, void *data, int error_status); + struct pam_data *next; +}; + +void _pam_free_data(pam_handle_t *pamh, int status); + +int _pam_strCMP(const char *s, const char *t); +char *_pam_StrTok(char *from, const char *format, char **next); + +char *_pam_strdup(const char *s); + +int _pam_mkargv(char *s, char ***argv, int *argc); + +void _pam_sanitize(pam_handle_t *pamh); + +void _pam_set_default_control(int *control_array, int default_action); + +void _pam_parse_control(int *control_array, char *tok); + +void _pam_system_log(int priority, const char *format, ... ); +#define _PAM_SYSTEM_LOG_PREFIX "PAM " + +/* + * XXX - Take care with this. It could confuse the logic of a trailing + * else + */ + +#define IF_NO_PAMH(X,pamh,ERR) \ +if ((pamh) == NULL) { \ + _pam_system_log(LOG_ERR, X ": NULL pam handle passed"); \ + return ERR; \ +} + +/* Definition for the default username prompt used by pam_get_user() */ + +#define PAM_DEFAULT_PROMPT "Please enter username: " + +/* + * include some helpful macros + */ + +#include <security/_pam_macros.h> + +/* used to work out where control currently resides (in an application + or in a module) */ + +#define _PAM_CALLED_FROM_MODULE 1 +#define _PAM_CALLED_FROM_APP 2 + +#define __PAM_FROM_MODULE(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_MODULE) +#define __PAM_FROM_APP(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_APP) +#define __PAM_TO_MODULE(pamh) \ + do { (pamh)->caller_is = _PAM_CALLED_FROM_MODULE; } while (0) +#define __PAM_TO_APP(pamh) \ + do { (pamh)->caller_is = _PAM_CALLED_FROM_APP; } while (0) + +/* + * Copyright (C) 1995 by Red Hat Software, Marc Ewing + * Copyright (c) 1996-8,2001 by Andrew G. Morgan <morgan@kernel.org> + * + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#endif /* _PAM_PRIVATE_H_ */ diff --git a/Linux-PAM/libpam/pam_second.c b/Linux-PAM/libpam/pam_second.c new file mode 100644 index 00000000..21b5b993 --- /dev/null +++ b/Linux-PAM/libpam/pam_second.c @@ -0,0 +1,50 @@ +/* + * pam_second.c -- PAM secondary authentication + * (based on XSSO draft spec of March 1997) + * + * $Id: pam_second.c,v 1.1.1.2 2002/09/15 20:08:39 hartmans Exp $ + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "pam_private.h" + +/* p 42 */ + +/* XXX - there are actually no plans to support this function. It does + not appear to be very well defined */ + +int pam_authenticate_secondary(pam_handle_t *pamh, + char *target_username, + char *target_module_type, + char *target_authn_domain, + char *target_supp_data, + unsigned char *target_module_authtok, + int flags); + +int pam_authenticate_secondary(pam_handle_t *pamh, + char *target_username, + char *target_module_type, + char *target_authn_domain, + char *target_supp_data, + unsigned char *target_module_authtok, + int flags) +{ + int retval=PAM_SYSTEM_ERR; + + D(("called")); + + _pam_start_timer(pamh); /* we try to make the time for a failure + independent of the time it takes to + fail */ + + IF_NO_PAMH("pam_authenticate_secondary",pamh,PAM_SYSTEM_ERR); + + _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ + + D(("pam_authenticate_secondary exit")); + + return retval; +} diff --git a/Linux-PAM/libpam/pam_session.c b/Linux-PAM/libpam/pam_session.c new file mode 100644 index 00000000..0ee5a61e --- /dev/null +++ b/Linux-PAM/libpam/pam_session.c @@ -0,0 +1,37 @@ +/* pam_session.c - PAM Session Management */ + +/* + * $Id: pam_session.c,v 1.1.1.1 2001/04/29 04:17:09 hartmans Exp $ + */ + +#include <stdio.h> + +#include "pam_private.h" + +int pam_open_session(pam_handle_t *pamh, int flags) +{ + D(("called")); + + IF_NO_PAMH("pam_open_session", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + return _pam_dispatch(pamh, flags, PAM_OPEN_SESSION); +} + +int pam_close_session(pam_handle_t *pamh, int flags) +{ + D(("called")); + + IF_NO_PAMH("pam_close_session", pamh, PAM_SYSTEM_ERR); + + if (__PAM_FROM_MODULE(pamh)) { + D(("called from module!?")); + return PAM_SYSTEM_ERR; + } + + return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION); +} diff --git a/Linux-PAM/libpam/pam_start.c b/Linux-PAM/libpam/pam_start.c new file mode 100644 index 00000000..53517fe0 --- /dev/null +++ b/Linux-PAM/libpam/pam_start.c @@ -0,0 +1,112 @@ +/* pam_start.c */ + +/* Creator Marc Ewing + * Maintained by AGM + * + * $Id: pam_start.c,v 1.1.1.1 2001/04/29 04:17:09 hartmans Exp $ + * + */ + +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> + +#include "pam_private.h" + +int pam_start ( + const char *service_name, + const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh) +{ + D(("called pam_start: [%s] [%s] [%p] [%p]" + ,service_name, user, pam_conversation, pamh)); + + if ((*pamh = calloc(1, sizeof(**pamh))) == NULL) { + _pam_system_log(LOG_CRIT, "pam_start: calloc failed for *pamh"); + return (PAM_BUF_ERR); + } + + /* Mark the caller as the application - permission to do certain + things is limited to a module or an application */ + + __PAM_TO_APP(*pamh); + + if (service_name) { + char *tmp; + + if (((*pamh)->service_name = _pam_strdup(service_name)) == NULL) { + _pam_system_log(LOG_CRIT, + "pam_start: _pam_strdup failed for service name"); + _pam_drop(*pamh); + return (PAM_BUF_ERR); + } + for (tmp=(*pamh)->service_name; *tmp; ++tmp) + *tmp = tolower(*tmp); /* require lower case */ + } else + (*pamh)->service_name = NULL; + + if (user) { + if (((*pamh)->user = _pam_strdup(user)) == NULL) { + _pam_system_log(LOG_CRIT, + "pam_start: _pam_strdup failed for user"); + _pam_drop((*pamh)->service_name); + _pam_drop(*pamh); + return (PAM_BUF_ERR); + } + } else + (*pamh)->user = NULL; + + (*pamh)->tty = NULL; + (*pamh)->prompt = NULL; /* prompt for pam_get_user() */ + (*pamh)->ruser = NULL; + (*pamh)->rhost = NULL; + (*pamh)->authtok = NULL; + (*pamh)->oldauthtok = NULL; + (*pamh)->fail_delay.delay_fn_ptr = NULL; + (*pamh)->former.choice = PAM_NOT_STACKED; + + if (pam_conversation == NULL + || ((*pamh)->pam_conversation = (struct pam_conv *) + malloc(sizeof(struct pam_conv))) == NULL) { + _pam_system_log(LOG_CRIT, "pam_start: malloc failed for pam_conv"); + _pam_drop((*pamh)->service_name); + _pam_drop((*pamh)->user); + _pam_drop(*pamh); + return (PAM_BUF_ERR); + } else { + memcpy((*pamh)->pam_conversation, pam_conversation, + sizeof(struct pam_conv)); + } + + (*pamh)->data = NULL; + if ( _pam_make_env(*pamh) != PAM_SUCCESS ) { + _pam_system_log(LOG_ERR,"pam_start: failed to initialize environment"); + _pam_drop((*pamh)->service_name); + _pam_drop((*pamh)->user); + _pam_drop(*pamh); + return PAM_ABORT; + } + + _pam_reset_timer(*pamh); /* initialize timer support */ + + _pam_start_handlers(*pamh); /* cannot fail */ + + /* According to the SunOS man pages, loading modules and resolving + * symbols happens on the first call from the application. */ + + if ( _pam_init_handlers(*pamh) != PAM_SUCCESS ) { + _pam_system_log(LOG_ERR, "pam_start: failed to initialize handlers"); + _pam_drop_env(*pamh); /* purge the environment */ + _pam_drop((*pamh)->service_name); + _pam_drop((*pamh)->user); + _pam_drop(*pamh); + return PAM_ABORT; + } + + D(("exiting pam_start successfully")); + + return PAM_SUCCESS; +} diff --git a/Linux-PAM/libpam/pam_static.c b/Linux-PAM/libpam/pam_static.c new file mode 100644 index 00000000..f7e0645f --- /dev/null +++ b/Linux-PAM/libpam/pam_static.c @@ -0,0 +1,141 @@ +/* pam_static.c -- static module loading helper functions */ + +/* created by Michael K. Johnson, johnsonm@redhat.com + * + * $Id: pam_static.c,v 1.1.1.1 2001/04/29 04:17:10 hartmans Exp $ + */ + +/* This whole file is only used for PAM_STATIC */ + +#ifdef PAM_STATIC + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "pam_private.h" + +/* + * Need to include pointers to static modules; this was built by each + * of the modules that register... + */ + +#include "../modules/_static_module_list" + +/* + * and here is a structure that connects libpam to the above static + * modules + */ + +static struct pam_module *static_modules[] = { + +#include "../modules/_static_module_entry" + + NULL +}; + +/* + * and now for the functions + */ + +/* Return pointer to data structure used to define a static module */ +struct pam_module * _pam_open_static_handler(const char *path) +{ + int i; + const char *clpath = path; + char *lpath, *end; + + if (strchr(clpath, '/')) { + /* ignore path and leading "/" */ + clpath = strrchr(lpath, '/') + 1; + } + /* create copy to muck with (must free before return) */ + lpath = _pam_strdup(clpath); + /* chop .so off copy if it exists (or other extension on other + platform...) */ + end = strstr(lpath, ".so"); + if (end) { + *end = '\0'; + } + + /* now go find the module */ + for (i = 0; static_modules[i] != NULL; i++) { + D(("%s=?%s\n", lpath, static_modules[i]->name)); + if (static_modules[i]->name && + ! strcmp(static_modules[i]->name, lpath)) { + break; + } + } + + if (static_modules[i] == NULL) { + _pam_system_log(NULL, NULL, LOG_ERR, "no static module named %s", + lpath); + } + + free(lpath); + return (static_modules[i]); +} + +/* Return pointer to function requested from static module + * Can't just return void *, because ANSI C disallows casting a + * pointer to a function to a void *... + * This definition means: + * _pam_get_static_sym is a function taking two arguments and + * returning a pointer to a function which takes no arguments + * and returns void... */ +voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname) { + + if (! strcmp(symname, "pam_sm_authenticate")) { + return ((voidfunc *)mod->pam_sm_authenticate); + } else if (! strcmp(symname, "pam_sm_setcred")) { + return ((voidfunc *)mod->pam_sm_setcred); + } else if (! strcmp(symname, "pam_sm_acct_mgmt")) { + return ((voidfunc *)mod->pam_sm_acct_mgmt); + } else if (! strcmp(symname, "pam_sm_open_session")) { + return ((voidfunc *)mod->pam_sm_open_session); + } else if (! strcmp(symname, "pam_sm_close_session")) { + return ((voidfunc *)mod->pam_sm_close_session); + } else if (! strcmp(symname, "pam_sm_chauthtok")) { + return ((voidfunc *)mod->pam_sm_chauthtok); + } + /* getting to this point is an error */ + return ((voidfunc *)NULL); +} + +#endif /* PAM_STATIC */ + +/* + * Copyright (C) 1995 by Red Hat Software, Michael K. Johnson + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/libpam/pam_strerror.c b/Linux-PAM/libpam/pam_strerror.c new file mode 100644 index 00000000..f287b5ad --- /dev/null +++ b/Linux-PAM/libpam/pam_strerror.c @@ -0,0 +1,93 @@ +/* pam_strerror.c */ + +/* + * $Id: pam_strerror.c,v 1.1.1.2 2002/09/15 20:08:39 hartmans Exp $ + */ + +#include "pam_private.h" + +const char *pam_strerror(pam_handle_t *pamh, int errnum) +{ +#ifdef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT /* will be removed from v 1.0 */ + + int possible_error; + + possible_error = (int) pamh; + if (!(possible_error >= 0 && possible_error <= PAM_BAD_ITEM)) { + possible_error = errnum; + } + +/* mask standard behavior to use possible_error variable. */ +#define errnum possible_error + +#endif /* UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT */ + + switch (errnum) { + case PAM_SUCCESS: + return "Success"; + case PAM_ABORT: + return "Critical error - immediate abort"; + case PAM_OPEN_ERR: + return "dlopen() failure"; + case PAM_SYMBOL_ERR: + return "Symbol not found"; + case PAM_SERVICE_ERR: + return "Error in service module"; + case PAM_SYSTEM_ERR: + return "System error"; + case PAM_BUF_ERR: + return "Memory buffer error"; + case PAM_PERM_DENIED: + return "Permission denied"; + case PAM_AUTH_ERR: + return "Authentication failure"; + case PAM_CRED_INSUFFICIENT: + return "Insufficient credentials to access authentication data"; + case PAM_AUTHINFO_UNAVAIL: + return "Authentication service cannot retrieve authentication info."; + case PAM_USER_UNKNOWN: + return "User not known to the underlying authentication module"; + case PAM_MAXTRIES: + return "Have exhasted maximum number of retries for service."; + case PAM_NEW_AUTHTOK_REQD: + return "Authentication token is no longer valid; new one required."; + case PAM_ACCT_EXPIRED: + return "User account has expired"; + case PAM_SESSION_ERR: + return "Cannot make/remove an entry for the specified session"; + case PAM_CRED_UNAVAIL: + return "Authentication service cannot retrieve user credentials"; + case PAM_CRED_EXPIRED: + return "User credentials expired"; + case PAM_CRED_ERR: + return "Failure setting user credentials"; + case PAM_NO_MODULE_DATA: + return "No module specific data is present"; + case PAM_BAD_ITEM: + return "Bad item passed to pam_*_item()"; + case PAM_CONV_ERR: + return "Conversation error"; + case PAM_AUTHTOK_ERR: + return "Authentication token manipulation error"; + case PAM_AUTHTOK_RECOVER_ERR: + return "Authentication information cannot be recovered"; + case PAM_AUTHTOK_LOCK_BUSY: + return "Authentication token lock busy"; + case PAM_AUTHTOK_DISABLE_AGING: + return "Authentication token aging disabled"; + case PAM_TRY_AGAIN: + return "Failed preliminary check by password service"; + case PAM_IGNORE: + return "Please ignore underlying account module"; + case PAM_MODULE_UNKNOWN: + return "Module is unknown"; + case PAM_AUTHTOK_EXPIRED: + return "Authentication token expired"; + case PAM_CONV_AGAIN: + return "Conversation is waiting for event"; + case PAM_INCOMPLETE: + return "Application needs to call libpam again"; + } + + return "Unknown PAM error"; +} diff --git a/Linux-PAM/libpam/pam_tokens.h b/Linux-PAM/libpam/pam_tokens.h new file mode 100644 index 00000000..0300fdf1 --- /dev/null +++ b/Linux-PAM/libpam/pam_tokens.h @@ -0,0 +1,106 @@ +/* + * pam_tokens.h + * + * $Id: pam_tokens.h,v 1.1.1.1 2001/04/29 04:17:10 hartmans Exp $ + * + * This is a Linux-PAM Library Private Header file. It contains tokens + * that are used when we parse the configuration file(s). + * + * Please see end of file for copyright. + * + * Creator: Andrew Morgan. + * + */ + +#ifndef _PAM_TOKENS_H +#define _PAM_TOKENS_H + +/* an array of actions */ + +const char * const _pam_token_actions[-_PAM_ACTION_UNDEF] = { + "ignore", /* 0 */ + "ok", /* -1 */ + "done", /* -2 */ + "bad", /* -3 */ + "die", /* -4 */ + "reset", /* -5 */ +}; + +/* an array of possible return values */ + +const char * const _pam_token_returns[_PAM_RETURN_VALUES+1] = { + "success", /* 0 */ + "open_err", /* 1 */ + "symbol_err", /* 2 */ + "service_err", /* 3 */ + "system_err", /* 4 */ + "buf_err", /* 5 */ + "perm_denied", /* 6 */ + "auth_err", /* 7 */ + "cred_insufficient", /* 8 */ + "authinfo_unavail", /* 9 */ + "user_unknown", /* 10 */ + "maxtries", /* 11 */ + "new_authtok_reqd", /* 12 */ + "acct_expired", /* 13 */ + "session_err", /* 14 */ + "cred_unavail", /* 15 */ + "cred_expired", /* 16 */ + "cred_err", /* 17 */ + "no_module_data", /* 18 */ + "conv_err", /* 19 */ + "authtok_err", /* 20 */ + "authtok_recover_err", /* 21 */ + "authtok_lock_busy", /* 22 */ + "authtok_disable_aging", /* 23 */ + "try_again", /* 24 */ + "ignore", /* 25 */ + "abort", /* 26 */ + "authtok_expired", /* 27 */ + "module_unknown", /* 28 */ + "bad_item", /* 29 */ + "conv_again", /* 30 */ + "incomplete", /* 31 */ +/* add new return codes here */ + "default" /* this is _PAM_RETURN_VALUES and indicates + the default return action */ +}; + +/* + * Copyright (C) 1998,2001 Andrew G. Morgan <morgan@kernel.org> + * + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#endif /* _PAM_PRIVATE_H_ */ diff --git a/Linux-PAM/libpam_misc/Makefile b/Linux-PAM/libpam_misc/Makefile new file mode 100644 index 00000000..8d5a68e6 --- /dev/null +++ b/Linux-PAM/libpam_misc/Makefile @@ -0,0 +1,107 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:40 hartmans Exp $ +# + +# lots of debugging information goes to /tmp/pam-debug.log +#MOREFLAGS += -D"DEBUG" + +include ../Make.Rules + +ifeq ($(WITH_LIBDEBUG),yes) + LIBNAME=libpam_miscd +else + LIBNAME=libpam_misc +endif +VERSION=.$(MAJOR_REL) +MODIFICATION=.$(MINOR_REL) + +CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC) +LINKLIBS += -L$(absolute_objdir)/libpam -lpam + +# dynamic library names + +LIBNAMED = $(LIBNAME).$(DYNTYPE) +LIBNAMEDNAME = $(LIBNAMED)$(VERSION) +LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION) + +# static library name + +LIBNAMEDSTATIC = $(LIBNAME).a + +LIBOBJECTS = help_env.o misc_conv.o + +ifeq ($(DYNAMIC_LIBPAM),yes) +DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS)) +endif + +ifeq ($(STATIC_LIBPAM),yes) +SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS)) +endif + +# --------------------------------------------- +## rules + +all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC) + +dirs: +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) dynamic +endif +ifeq ($(STATIC_LIBPAM),yes) + $(MKDIR) static +endif + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(LIBNAMED): $(DLIBOBJECTS) +ifeq ($(DYNAMIC_LIBPAM),yes) + ifeq ($(USESONAME),yes) + $(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) + else + $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) + endif + ifeq ($(NEEDSONAME),yes) + rm -f $(LIBNAMEDFULL) + ln -s $(LIBNAMED) $(LIBNAMEDFULL) + rm -f $(LIBNAMEDNAME) + ln -s $(LIBNAMED) $(LIBNAMEDNAME) + endif +endif + +$(LIBNAMEDSTATIC): $(SLIBOBJECTS) +ifeq ($(STATIC_LIBPAM),yes) + $(AR) rc $@ $(SLIBOBJECTS) $(MODULES) + $(RANLIB) $@ +endif + +install: all + $(MKDIR) $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/pam_misc.h $(FAKEROOT)$(INCLUDED) +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) $(FAKEROOT)$(libdir) + $(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) + $(LDCONFIG) + ifneq ($(DYNTYPE),"sl") + ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) ) + endif +endif +ifeq ($(STATIC_LIBPAM),yes) + $(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir) +endif + +remove: + rm -f $(FAKEROOT)$(INCLUDED)/pam_misc.h + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED) + $(LDCONFIG) + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC) + +clean: + rm -f a.out core *~ static/*.o dynamic/*.o + rm -f *.a *.out *.o *.so ./include/security/*~ + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi diff --git a/Linux-PAM/libpam_misc/help_env.c b/Linux-PAM/libpam_misc/help_env.c new file mode 100644 index 00000000..3a342ed5 --- /dev/null +++ b/Linux-PAM/libpam_misc/help_env.c @@ -0,0 +1,105 @@ +/* + * $Id: help_env.c,v 1.1.1.1 2001/04/29 04:17:12 hartmans Exp $ + * + * This file was written by Andrew G. Morgan <morgan@parc.power.net> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <security/pam_misc.h> + +/* + * This is a useful function for dumping the Linux-PAM environment + * into some local memory, prior to it all getting lost when pam_end() + * is called. + * + * Initially it was assumed that libpam did not do this part correctly + * (based on a loose email definition). The X/Open XSSO spec makes it + * clear that this function is a duplicate of the one already in + * libpam and therefore unnecessary. IT WILL BE COMPLETELY REMOVED + * IN libpam_misc 1.0 */ + +char **pam_misc_copy_env(pam_handle_t *pamh); +char **pam_misc_copy_env(pam_handle_t *pamh) +{ + return pam_getenvlist(pamh); +} + +/* + * This function should be used to carefully dispose of the copied + * environment. + * + * usage: env = pam_misc_drop_env(env); + */ + +char **pam_misc_drop_env(char **dump) +{ + int i; + + for (i=0; dump[i] != NULL; ++i) { + D(("dump[%d]=`%s'", i, dump[i])); + _pam_overwrite(dump[i]); + _pam_drop(dump[i]); + } + _pam_drop(dump); + + return NULL; +} + +/* + * This function takes the supplied environment and uploads it to be + * the PAM one. + */ + +int pam_misc_paste_env(pam_handle_t *pamh, const char * const * user_env) +{ + for (; user_env && *user_env; ++user_env) { + int retval; + + D(("uploading: %s", *user_env)); + retval = pam_putenv(pamh, *user_env); + if (retval != PAM_SUCCESS) { + D(("error setting %s: %s", *user_env, pam_strerror(pamh,retval))); + return retval; + } + } + D(("done.")); + return PAM_SUCCESS; +} + +/* + * This is a wrapper to make pam behave in the way that setenv() does. + */ + +int pam_misc_setenv(pam_handle_t *pamh, const char *name + , const char *value, int readonly) +{ + char *tmp; + int retval; + + if (readonly) { + const char *etmp; + + /* we check if the variable is there already */ + etmp = pam_getenv(pamh, name); + if (etmp != NULL) { + D(("failed to set readonly variable: %s", name)); + return PAM_PERM_DENIED; /* not allowed to overwrite */ + } + } + tmp = malloc(2+strlen(name)+strlen(value)); + if (tmp != NULL) { + sprintf(tmp,"%s=%s",name,value); + D(("pam_putt()ing: %s", tmp)); + retval = pam_putenv(pamh, tmp); + _pam_overwrite(tmp); /* purge */ + _pam_drop(tmp); /* forget */ + } else { + D(("malloc failure")); + retval = PAM_BUF_ERR; + } + + return retval; +} diff --git a/Linux-PAM/libpam_misc/include/security/pam_misc.h b/Linux-PAM/libpam_misc/include/security/pam_misc.h new file mode 100644 index 00000000..e042e8e9 --- /dev/null +++ b/Linux-PAM/libpam_misc/include/security/pam_misc.h @@ -0,0 +1,62 @@ +/* $Id: pam_misc.h,v 1.1.1.2 2002/09/15 20:08:41 hartmans Exp $ */ + +#ifndef __PAMMISC_H +#define __PAMMISC_H + +#include <security/pam_appl.h> +#include <security/pam_client.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* include some useful macros */ + +#include <security/_pam_macros.h> + +/* functions defined in pam_misc.* libraries */ + +extern int misc_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr); + +#include <time.h> + +extern time_t pam_misc_conv_warn_time; /* time that we should warn user */ +extern time_t pam_misc_conv_die_time; /* cut-off time for input */ +extern const char *pam_misc_conv_warn_line; /* warning notice */ +extern const char *pam_misc_conv_die_line; /* cut-off remark */ +extern int pam_misc_conv_died; /* 1 = cut-off time reached (0 not) */ +extern int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p); +extern void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p); +/* + * Environment helper functions + */ + +/* transcribe given environment (to pam) */ +extern int pam_misc_paste_env(pam_handle_t *pamh + , const char * const * user_env); + +/* char **pam_misc_copy_env(pam_handle_t *pamh); + + This is no longer defined as a prototype because the X/Open XSSO + spec makes it clear that PAM's pam_getenvlist() does exactly + what this was needed for. + + A wrapper is still provided in the pam_misc library - so that + legacy applications will still work. But _BE_WARNED_ it will + disappear by the release of libpam 1.0 . */ + +/* delete environment as obtained from (pam_getenvlist) */ +extern char **pam_misc_drop_env(char **env); + +/* provide something like the POSIX setenv function for the (Linux-)PAM + * environment. */ + +extern int pam_misc_setenv(pam_handle_t *pamh, const char *name + , const char *value, int readonly); + +#ifdef __cplusplus +} +#endif /* def __cplusplus */ + +#endif /* ndef __PAMMISC_H */ diff --git a/Linux-PAM/libpam_misc/misc_conv.c b/Linux-PAM/libpam_misc/misc_conv.c new file mode 100644 index 00000000..e352bb9a --- /dev/null +++ b/Linux-PAM/libpam_misc/misc_conv.c @@ -0,0 +1,380 @@ +/* + * $Id: misc_conv.c,v 1.1.1.2 2002/09/15 20:08:40 hartmans Exp $ + * + * A generic conversation function for text based applications + * + * Written by Andrew Morgan <morgan@linux.kernel.org> + */ + +#include <security/_pam_aconf.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +#define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */ +#define CONV_ECHO_ON 1 /* types of echo state */ +#define CONV_ECHO_OFF 0 + +/* + * external timeout definitions - these can be overriden by the + * application. + */ + +time_t pam_misc_conv_warn_time = 0; /* time when we warn */ +time_t pam_misc_conv_die_time = 0; /* time when we timeout */ + +const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n"; +const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n"; + +int pam_misc_conv_died=0; /* application can probe this for timeout */ + +/* + * These functions are for binary prompt manipulation. + * The manner in which a binary prompt is processed is application + * specific, so these function pointers are provided and can be + * initialized by the application prior to the conversation function + * being used. + */ + +static void pam_misc_conv_delete_binary(void *appdata, + pamc_bp_t *delete_me) +{ + PAM_BP_RENEW(delete_me, 0, 0); +} + +int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL; +void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p) + = pam_misc_conv_delete_binary; + +/* the following code is used to get text input */ + +static volatile int expired=0; + +/* return to the previous signal handling */ +static void reset_alarm(struct sigaction *o_ptr) +{ + (void) alarm(0); /* stop alarm clock - if still ticking */ + (void) sigaction(SIGALRM, o_ptr, NULL); +} + +/* this is where we intercept the alarm signal */ +static void time_is_up(int ignore) +{ + expired = 1; +} + +/* set the new alarm to hit the time_is_up() function */ +static int set_alarm(int delay, struct sigaction *o_ptr) +{ + struct sigaction new_sig; + + sigemptyset(&new_sig.sa_mask); + new_sig.sa_flags = 0; + new_sig.sa_handler = time_is_up; + if ( sigaction(SIGALRM, &new_sig, o_ptr) ) { + return 1; /* setting signal failed */ + } + if ( alarm(delay) ) { + (void) sigaction(SIGALRM, o_ptr, NULL); + return 1; /* failed to set alarm */ + } + return 0; /* all seems to have worked */ +} + +/* return the number of seconds to next alarm. 0 = no delay, -1 = expired */ +static int get_delay(void) +{ + time_t now; + + expired = 0; /* reset flag */ + (void) time(&now); + + /* has the quit time past? */ + if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) { + fprintf(stderr,"%s",pam_misc_conv_die_line); + + pam_misc_conv_died = 1; /* note we do not reset the die_time */ + return -1; /* time is up */ + } + + /* has the warning time past? */ + if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) { + fprintf(stderr, "%s", pam_misc_conv_warn_line); + pam_misc_conv_warn_time = 0; /* reset warn_time */ + + /* indicate remaining delay - if any */ + + return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now:0 ); + } + + /* indicate possible warning delay */ + + if (pam_misc_conv_warn_time) + return (pam_misc_conv_warn_time - now); + else if (pam_misc_conv_die_time) + return (pam_misc_conv_die_time - now); + else + return 0; +} + +/* read a line of input string, giving prompt when appropriate */ +static char *read_string(int echo, const char *prompt) +{ + struct termios term_before, term_tmp; + char line[INPUTSIZE], *input; + struct sigaction old_sig; + int delay, nc, have_term=0; + sigset_t oset, nset; + + D(("called with echo='%s', prompt='%s'.", echo ? "ON":"OFF" , prompt)); + + input = line; + + if (isatty(STDIN_FILENO)) { /* terminal state */ + + /* is a terminal so record settings and flush it */ + if ( tcgetattr(STDIN_FILENO, &term_before) != 0 ) { + D(("<error: failed to get terminal settings>")); + return NULL; + } + memcpy(&term_tmp, &term_before, sizeof(term_tmp)); + if (!echo) { + term_tmp.c_lflag &= ~(ECHO); + } + have_term = 1; + + /* + * We make a simple attempt to block TTY signals from terminating + * the conversation without giving PAM a chance to clean up. + */ + + sigemptyset(&nset); + sigaddset(&nset, SIGINT); + sigaddset(&nset, SIGTSTP); + (void) sigprocmask(SIG_BLOCK, &nset, &oset); + + } else if (!echo) { + D(("<warning: cannot turn echo off>")); + } + + /* set up the signal handling */ + delay = get_delay(); + + /* reading the line */ + while (delay >= 0) { + + fprintf(stderr, "%s", prompt); + /* this may, or may not set echo off -- drop pending input */ + if (have_term) + (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp); + + if ( delay > 0 && set_alarm(delay, &old_sig) ) { + D(("<failed to set alarm>")); + break; + } else { + nc = read(STDIN_FILENO, line, INPUTSIZE-1); + if (have_term) { + (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); + if (!echo || expired) /* do we need a newline? */ + fprintf(stderr,"\n"); + } + if ( delay > 0 ) { + reset_alarm(&old_sig); + } + if (expired) { + delay = get_delay(); + } else if (nc > 0) { /* we got some user input */ + D(("we got some user input")); + + if (nc > 0 && line[nc-1] == '\n') { /* <NUL> terminate */ + line[--nc] = '\0'; + } else { + if (echo) { + fprintf(stderr, "\n"); + } + line[nc] = '\0'; + } + input = x_strdup(line); + _pam_overwrite(line); + + goto cleanexit; /* return malloc()ed string */ + + } else if (nc == 0) { /* Ctrl-D */ + D(("user did not want to type anything")); + + input = x_strdup(""); + if (echo) { + fprintf(stderr, "\n"); + } + goto cleanexit; /* return malloc()ed "" */ + } + } + } + + /* getting here implies that the timer expired */ + + D(("the timer appears to have expired")); + + input = NULL; + _pam_overwrite(line); + + cleanexit: + + if (have_term) { + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); + } + + D(("returning [%s]", input)); + + return input; +} + +/* end of read_string functions */ + +/* + * This conversation function is supposed to be a generic PAM one. + * Unfortunately, it is _not_ completely compatible with the Solaris PAM + * codebase. + * + * Namely, for msgm's that contain multiple prompts, this function + * interprets "const struct pam_message **msgm" as equivalent to + * "const struct pam_message *msgm[]". The Solaris module + * implementation interprets the **msgm object as a pointer to a + * pointer to an array of "struct pam_message" objects (that is, a + * confusing amount of pointer indirection). + */ + +int misc_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int count=0; + struct pam_response *reply; + + if (num_msg <= 0) + return PAM_CONV_ERR; + + D(("allocating empty response structure array.")); + + reply = (struct pam_response *) calloc(num_msg, + sizeof(struct pam_response)); + if (reply == NULL) { + D(("no memory for responses")); + return PAM_CONV_ERR; + } + + D(("entering conversation function.")); + + for (count=0; count < num_msg; ++count) { + char *string=NULL; + + switch (msgm[count]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + string = read_string(CONV_ECHO_OFF,msgm[count]->msg); + if (string == NULL) { + goto failed_conversation; + } + break; + case PAM_PROMPT_ECHO_ON: + string = read_string(CONV_ECHO_ON,msgm[count]->msg); + if (string == NULL) { + goto failed_conversation; + } + break; + case PAM_ERROR_MSG: + if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) { + goto failed_conversation; + } + break; + case PAM_TEXT_INFO: + if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) { + goto failed_conversation; + } + break; + case PAM_BINARY_PROMPT: + { + pamc_bp_t binary_prompt = NULL; + + if (!msgm[count]->msg || !pam_binary_handler_fn) { + goto failed_conversation; + } + + PAM_BP_RENEW(&binary_prompt, + PAM_BP_RCONTROL(msgm[count]->msg), + PAM_BP_LENGTH(msgm[count]->msg)); + PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg), + PAM_BP_RDATA(msgm[count]->msg)); + + if (pam_binary_handler_fn(appdata_ptr, + &binary_prompt) != PAM_SUCCESS + || (binary_prompt == NULL)) { + goto failed_conversation; + } + string = (char *) binary_prompt; + binary_prompt = NULL; + + break; + } + default: + fprintf(stderr, "erroneous conversation (%d)\n" + ,msgm[count]->msg_style); + goto failed_conversation; + } + + if (string) { /* must add to reply array */ + /* add string to list of responses */ + + reply[count].resp_retcode = 0; + reply[count].resp = string; + string = NULL; + } + } + + *response = reply; + reply = NULL; + + return PAM_SUCCESS; + +failed_conversation: + + D(("the conversation failed")); + + if (reply) { + for (count=0; count<num_msg; ++count) { + if (reply[count].resp == NULL) { + continue; + } + switch (msgm[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + _pam_overwrite(reply[count].resp); + free(reply[count].resp); + break; + case PAM_BINARY_PROMPT: + pam_binary_handler_free(appdata_ptr, + (pamc_bp_t *) &reply[count].resp); + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + /* should not actually be able to get here... */ + free(reply[count].resp); + } + reply[count].resp = NULL; + } + /* forget reply too */ + free(reply); + reply = NULL; + } + + return PAM_CONV_ERR; +} + diff --git a/Linux-PAM/libpam_misc/xstrdup.c b/Linux-PAM/libpam_misc/xstrdup.c new file mode 100644 index 00000000..f5bfde66 --- /dev/null +++ b/Linux-PAM/libpam_misc/xstrdup.c @@ -0,0 +1,31 @@ +/* $Id: xstrdup.c,v 1.1.1.1 2001/04/29 04:17:12 hartmans Exp $ */ + +#include <malloc.h> +#include <string.h> +#include <security/pam_misc.h> + +/* + * Safe duplication of character strings. "Paranoid"; don't leave + * evidence of old token around for later stack analysis. + */ + +char *xstrdup(const char *x) +{ + register char *new=NULL; + + if (x != NULL) { + register int i; + + for (i=0; x[i]; ++i); /* length of string */ + if ((new = malloc(++i)) == NULL) { + i = 0; + } else { + while (i-- > 0) { + new[i] = x[i]; + } + } + x = NULL; + } + + return new; /* return the duplicate or NULL on error */ +} diff --git a/Linux-PAM/libpamc/License b/Linux-PAM/libpamc/License new file mode 100644 index 00000000..90106954 --- /dev/null +++ b/Linux-PAM/libpamc/License @@ -0,0 +1,42 @@ +Unless otherwise *explicitly* stated the following text describes the +licensed conditions under which the contents of this libpamc release +may be distributed: + +------------------------------------------------------------------------- +Redistribution and use in source and binary forms of libpamc, +with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU Library General Public License (LGPL), in which case the +provisions of the GNU LGPL are required INSTEAD OF the above +restrictions. (This clause is necessary due to a potential conflict +between the GNU LGPL and the restrictions contained in a BSD-style +copyright.) + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +------------------------------------------------------------------------- + diff --git a/Linux-PAM/libpamc/Makefile b/Linux-PAM/libpamc/Makefile new file mode 100644 index 00000000..f1c90669 --- /dev/null +++ b/Linux-PAM/libpamc/Makefile @@ -0,0 +1,107 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:13 hartmans Exp $ +# + +# lots of debugging information goes to /tmp/pam-debug.log +#MOREFLAGS += -D"DEBUG" + +include ../Make.Rules + +ifeq ($(DEBUG_REL),yes) + LIBNAME=libpamcd +else + LIBNAME=libpamc +endif +VERSION=.$(MAJOR_REL) +MODIFICATION=.$(MINOR_REL) + +CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC) + +# dynamic library names + +LIBNAMED = $(LIBNAME).$(DYNTYPE) +LIBNAMEDNAME = $(LIBNAMED)$(VERSION) +LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION) + +# static library name + +LIBNAMEDSTATIC = $(LIBNAME).a + +LIBOBJECTS = pamc_client.o pamc_converse.o pamc_load.o + +ifeq ($(DYNAMIC_LIBPAM),yes) +DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS)) +endif + +ifeq ($(STATIC_LIBPAM),yes) +SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS)) +endif + +# --------------------------------------------- +## rules + +all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC) + +dirs: +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) dynamic +endif +ifeq ($(STATIC_LIBPAM),yes) + $(MKDIR) static +endif + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(LIBNAMED): $(DLIBOBJECTS) +ifeq ($(DYNAMIC_LIBPAM),yes) + ifeq ($(USESONAME),yes) + $(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) + else + $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) + endif + ifeq ($(NEEDSONAME),yes) + rm -f $(LIBNAMEDFULL) + ln -s $(LIBNAMED) $(LIBNAMEDFULL) + rm -f $(LIBNAMEDNAME) + ln -s $(LIBNAMED) $(LIBNAMEDNAME) + endif +endif + +$(LIBNAMEDSTATIC): $(SLIBOBJECTS) +ifeq ($(STATIC_LIBPAM),yes) + $(AR) rc $@ $(SLIBOBJECTS) $(MODULES) + $(RANLIB) $@ +endif + +install: all + $(MKDIR) $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/pam_client.h $(FAKEROOT)$(INCLUDED) +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) $(FAKEROOT)$(libdir) + $(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) + $(LDCONFIG) + ifneq ($(DYNTYPE),"sl") + ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) ) + endif +endif +ifeq ($(STATIC_LIBPAM),yes) + $(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir) +endif + +remove: + rm -f $(FAKEROOT)$(INCLUDED)/pam_client.h + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED) + $(LDCONFIG) + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC) + +clean: + rm -f a.out core *~ static/*.o dynamic/*.o + rm -f *.a *.out *.o *.so ./include/security/*~ + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi + diff --git a/Linux-PAM/libpamc/include/security/pam_client.h b/Linux-PAM/libpamc/include/security/pam_client.h new file mode 100644 index 00000000..7c474689 --- /dev/null +++ b/Linux-PAM/libpamc/include/security/pam_client.h @@ -0,0 +1,197 @@ +/* + * $Id: pam_client.h,v 1.1.1.2 2002/09/15 20:08:42 hartmans Exp $ + * + * Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org> + * + * This header file provides the prototypes for the PAM client API + */ + +#ifndef PAM_CLIENT_H +#define PAM_CLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif /* def __cplusplus */ + +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +/* opaque agent handling structure */ + +typedef struct pamc_handle_s *pamc_handle_t; + +/* binary prompt structure pointer */ +#ifndef __u32 +# define __u32 unsigned int +#endif +#ifndef __u8 +# define __u8 unsigned char +#endif +typedef struct { __u32 length; __u8 control; } *pamc_bp_t; + +/* + * functions provided by libpamc + */ + +/* + * Initialize the agent abstraction library + */ + +pamc_handle_t pamc_start(void); + +/* + * Terminate the authentication process + */ + +int pamc_end(pamc_handle_t *pch); + +/* + * force the loading of a specified agent + */ + +int pamc_load(pamc_handle_t pch, const char *agent_id); + +/* + * Single conversation interface for binary prompts + */ + +int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p); + +/* + * disable an agent + */ + +int pamc_disable(pamc_handle_t pch, const char *agent_id); + +/* + * obtain a list of available agents + */ + +char **pamc_list_agents(pamc_handle_t pch); + +/* + * PAM_BP_ MACROS for creating, destroying and manipulating binary prompts + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#ifndef PAM_BP_ASSERT +# define PAM_BP_ASSERT(x) do { printf(__FILE__ "(%d): %s\n", \ + __LINE__, x) ; exit(1); } while (0) +#endif /* PAM_BP_ASSERT */ + +#ifndef PAM_BP_CALLOC +# define PAM_BP_CALLOC calloc +#endif /* PAM_BP_CALLOC */ + +#ifndef PAM_BP_FREE +# define PAM_BP_FREE free +#endif /* PAM_BP_FREE */ + +#define __PAM_BP_WOCTET(x,y) (*((y) + (__u8 *)(x))) +#define __PAM_BP_ROCTET(x,y) (*((y) + (const __u8 *)(x))) + +#define PAM_BP_MIN_SIZE (sizeof(__u32) + sizeof(__u8)) +#define PAM_BP_MAX_LENGTH 0x20000 /* an advisory limit */ +#define PAM_BP_WCONTROL(x) (__PAM_BP_WOCTET(x,4)) +#define PAM_BP_RCONTROL(x) (__PAM_BP_ROCTET(x,4)) +#define PAM_BP_SIZE(x) ((__PAM_BP_ROCTET(x,0)<<24)+ \ + (__PAM_BP_ROCTET(x,1)<<16)+ \ + (__PAM_BP_ROCTET(x,2)<< 8)+ \ + (__PAM_BP_ROCTET(x,3) )) +#define PAM_BP_LENGTH(x) (PAM_BP_SIZE(x) - PAM_BP_MIN_SIZE) +#define PAM_BP_WDATA(x) (PAM_BP_MIN_SIZE + (__u8 *) (x)) +#define PAM_BP_RDATA(x) (PAM_BP_MIN_SIZE + (const __u8 *) (x)) + +/* Note, this macro always '\0' terminates renewed packets */ + +#define PAM_BP_RENEW(old_p, cntrl, data_length) \ +do { \ + if (old_p) { \ + if (*(old_p)) { \ + __u32 __size; \ + __size = PAM_BP_SIZE(*(old_p)); \ + memset(*(old_p), 0, __size); \ + PAM_BP_FREE(*(old_p)); \ + } \ + if (cntrl) { \ + __u32 __size; \ + \ + __size = PAM_BP_MIN_SIZE + data_length; \ + if ((*(old_p) = PAM_BP_CALLOC(1, 1+__size))) { \ + __PAM_BP_WOCTET(*(old_p), 3) = __size & 0xFF; \ + __PAM_BP_WOCTET(*(old_p), 2) = (__size>>=8) & 0xFF; \ + __PAM_BP_WOCTET(*(old_p), 1) = (__size>>=8) & 0xFF; \ + __PAM_BP_WOCTET(*(old_p), 0) = (__size>>=8) & 0xFF; \ + (*(old_p))->control = cntrl; \ + } else { \ + PAM_BP_ASSERT("out of memory for binary prompt"); \ + } \ + } else { \ + *old_p = NULL; \ + } \ + } else { \ + PAM_BP_ASSERT("programming error, invalid binary prompt pointer"); \ + } \ +} while (0) + +#define PAM_BP_FILL(prmpt, offset, length, data) \ +do { \ + size_t bp_length; \ + __u8 *prompt = (__u8 *) (prmpt); \ + bp_length = PAM_BP_LENGTH(prompt); \ + if (bp_length < ((length)+(offset))) { \ + PAM_BP_ASSERT("attempt to write over end of prompt"); \ + } \ + memcpy((offset) + PAM_BP_WDATA(prompt), (data), (length)); \ +} while (0) + +#define PAM_BP_EXTRACT(prmpt, offset, length, data) \ +do { \ + size_t __bp_length; \ + const __u8 *__prompt = (const __u8 *) (prmpt); \ + __bp_length = PAM_BP_LENGTH(__prompt); \ + if (((offset) < 0) || (__bp_length < ((length)+(offset))) \ + || ((length) < 0)) { \ + PAM_BP_ASSERT("invalid extraction from prompt"); \ + } \ + memcpy((data), (offset) + PAM_BP_RDATA(__prompt), (length)); \ +} while (0) + + +/* Control types */ + +#define PAM_BPC_FALSE 0 +#define PAM_BPC_TRUE 1 + +#define PAM_BPC_OK 0x01 /* continuation packet */ +#define PAM_BPC_SELECT 0x02 /* initialization packet */ +#define PAM_BPC_DONE 0x03 /* termination packet */ +#define PAM_BPC_FAIL 0x04 /* unable to execute */ + +/* The following control characters are only legal for echanges + between an agent and a client (it is the responsibility of the + client to enforce this rule in the face of a rogue server): */ + +#define PAM_BPC_GETENV 0x41 /* obtain client env.var */ +#define PAM_BPC_PUTENV 0x42 /* set client env.var */ +#define PAM_BPC_TEXT 0x43 /* display message */ +#define PAM_BPC_ERROR 0x44 /* display error message */ +#define PAM_BPC_PROMPT 0x45 /* echo'd text prompt */ +#define PAM_BPC_PASS 0x46 /* non-echo'd text prompt*/ + +/* quick check for prompts that are legal for the client (by + implication the server too) to send to libpamc */ + +#define PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt) \ + (((prompt)->control <= PAM_BPC_FAIL && (prompt)->control >= PAM_BPC_OK) \ + ? PAM_BPC_TRUE:PAM_BPC_FALSE) + +#ifdef __cplusplus +} +#endif /* def __cplusplus */ + +#endif /* PAM_CLIENT_H */ diff --git a/Linux-PAM/libpamc/libpamc.h b/Linux-PAM/libpamc/libpamc.h new file mode 100644 index 00000000..4b47029f --- /dev/null +++ b/Linux-PAM/libpamc/libpamc.h @@ -0,0 +1,63 @@ +/* + * $Id: libpamc.h,v 1.1.1.1 2001/04/29 04:17:13 hartmans Exp $ + * + * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> + * + */ + +#ifndef LIBPAMC_H +#define LIBPAMC_H + +#include <security/pam_client.h> +#include <security/_pam_macros.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +#define _PAMC_DEFAULT_TOP_FD 10 + +struct pamc_handle_s { + struct pamc_agent_s *current; + struct pamc_agent_s *chain; + struct pamc_blocked_s *blocked_agents; + int max_path; + char **agent_paths; + int combined_status; + int highest_fd_to_close; +}; + +typedef struct pamc_blocked_s { + char *id; /* <NUL> terminated */ + struct pamc_blocked_s *next; +} pamc_blocked_t; + +typedef struct pamc_agent_s { + char *id; + int id_length; + struct pamc_agent_s *next; + int writer; /* write to agent */ + int reader; /* read from agent */ + pid_t pid; /* agent process id */ +} pamc_agent_t; + +/* used to build a tree of unique, sorted agent ids */ + +typedef struct pamc_id_node { + struct pamc_id_node *left, *right; + int child_count; + char *agent_id; +} pamc_id_node_t; + +/* internal function */ +int __pamc_valid_agent_id(int id_length, const char *id); + +#define PAMC_SYSTEM_AGENT_PATH "/lib/pamc:/usr/lib/pamc" +#define PAMC_SYSTEM_AGENT_SEPARATOR ':' + +#endif /* LIBPAMC_H */ diff --git a/Linux-PAM/libpamc/pamc_client.c b/Linux-PAM/libpamc/pamc_client.c new file mode 100644 index 00000000..82d61262 --- /dev/null +++ b/Linux-PAM/libpamc/pamc_client.c @@ -0,0 +1,189 @@ +/* + * $Id: pamc_client.c,v 1.1.1.1 2001/04/29 04:17:13 hartmans Exp $ + * + * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> + * + * pamc_start and pamc_end + */ + +#include "libpamc.h" + +/* + * liberate path list + */ + +static void __pamc_delete_path_list(pamc_handle_t pch) +{ + int i; + + for (i=0; pch->agent_paths[i]; ++i) { + free(pch->agent_paths[i]); + pch->agent_paths[i] = NULL; + } + + free(pch->agent_paths); + pch->agent_paths = NULL; +} + +/* + * open the pamc library + */ + +pamc_handle_t pamc_start(void) +{ + int i, count, last, this; + const char *default_path; + pamc_handle_t pch; + + pch = calloc(1, sizeof(struct pamc_handle_s)); + if (pch == NULL) { + D(("no memory for *pch")); + return NULL; + } + + pch->highest_fd_to_close = _PAMC_DEFAULT_TOP_FD; + + default_path = getenv("PAMC_AGENT_PATH"); + if (default_path == NULL) { + default_path = PAMC_SYSTEM_AGENT_PATH; + } + + /* number of individual paths */ + for (count=1, i=0; default_path[i]; ++i) { + if (default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR) { + ++count; + } + } + + pch->agent_paths = calloc(count+1, sizeof(char *)); + if (pch->agent_paths == NULL) { + D(("no memory for path list")); + goto drop_pch; + } + + this = last = i = 0; + while ( default_path[i] || (i != last) ) { + if ( default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR + || !default_path[i] ) { + int length; + + pch->agent_paths[this] = malloc(length = 1+i-last); + + if (pch->agent_paths[this] == NULL) { + D(("no memory for next path")); + goto drop_list; + } + + memcpy(pch->agent_paths[this], default_path + last, i-last); + pch->agent_paths[this][i-last] = '\0'; + if (length > pch->max_path) { + pch->max_path = length; + } + + if (++this == count) { + break; + } + + last = ++i; + } else { + ++i; + } + } + + return pch; + +drop_list: + __pamc_delete_path_list(pch); + +drop_pch: + free(pch); + + return NULL; +} + +/* + * shutdown each of the loaded agents and + */ + +static int __pamc_shutdown_agents(pamc_handle_t pch) +{ + int retval = PAM_BPC_TRUE; + + D(("called")); + + while (pch->chain) { + pid_t pid; + int status; + pamc_agent_t *this; + + this = pch->chain; + D(("cleaning up agent %p", this)); + pch->chain = pch->chain->next; + this->next = NULL; + D(("cleaning up agent: %s", this->id)); + + /* close off contact with agent and wait for it to shutdown */ + + close(this->writer); + this->writer = -1; + close(this->reader); + this->reader = -1; + + pid = waitpid(this->pid, &status, 0); + if (pid == this->pid) { + + D(("is exit:%d, exit val:%d", + WIFEXITED(status), WEXITSTATUS(status))); + + if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) { + retval = PAM_BPC_FALSE; + } + } else { + D(("problem shutting down agent (%s): pid(%d) != waitpid(%d)!?", + this->id, this->pid, pid)); + retval = PAM_BPC_FALSE; + } + pid = this->pid = 0; + + memset(this->id, 0, this->id_length); + free(this->id); + this->id = NULL; + this->id_length = 0; + + free(this); + this = NULL; + } + + return retval; +} + +/* + * close the pamc library + */ + +int pamc_end(pamc_handle_t *pch_p) +{ + int retval; + + if (pch_p == NULL) { + D(("called with no pch_p")); + return PAM_BPC_FALSE; + } + + if (*pch_p == NULL) { + D(("called with no *pch_p")); + return PAM_BPC_FALSE; + } + + D(("removing path_list")); + __pamc_delete_path_list(*pch_p); + + D(("shutting down agents")); + retval = __pamc_shutdown_agents(*pch_p); + + D(("freeing *pch_p")); + free(*pch_p); + *pch_p = NULL; + + return retval; +} diff --git a/Linux-PAM/libpamc/pamc_converse.c b/Linux-PAM/libpamc/pamc_converse.c new file mode 100644 index 00000000..426f581d --- /dev/null +++ b/Linux-PAM/libpamc/pamc_converse.c @@ -0,0 +1,211 @@ +/* + * $Id: pamc_converse.c,v 1.1.1.1 2001/04/29 04:17:13 hartmans Exp $ + * + * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> + * + * pamc_converse + */ + +#include "libpamc.h" + +/* + * select agent + */ + +static int __pamc_select_agent(pamc_handle_t pch, char *agent_id) +{ + pamc_agent_t *agent; + + for (agent = pch->chain; agent; agent = agent->next) { + if (!strcmp(agent->id, agent_id)) { + pch->current = agent; + return PAM_BPC_TRUE; + } + } + + D(("failed to locate agent")); + pch->current = NULL; + return PAM_BPC_FALSE; +} + +/* + * pass a binary prompt to the active agent and wait for a reply prompt + */ + +int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p) +{ + __u32 size, offset=0; + __u8 control, raw[PAM_BP_MIN_SIZE]; + + D(("called")); + + if (pch == NULL) { + D(("null pch")); + goto pamc_converse_failure; + } + + if (prompt_p == NULL) { + D(("null prompt_p")); + goto pamc_converse_failure; + } + + if (*prompt_p == NULL) { + D(("null *prompt_p")); + goto pamc_converse_failure; + } + + /* from here on, failures are interoperability problems.. */ + + size = PAM_BP_SIZE(*prompt_p); + if (size < PAM_BP_MIN_SIZE) { + D(("problem with size being too short (%u)", size)); + goto pamc_unknown_prompt; + } + + if (PAM_BPC_FOR_CLIENT(*prompt_p) != PAM_BPC_TRUE) { + D(("*prompt_p is not legal for the client to use")); + goto pamc_unknown_prompt; + } + + /* do we need to select the agent? */ + if ((*prompt_p)->control == PAM_BPC_SELECT) { + char *rawh; + int i, retval; + + D(("selecting a specified agent")); + + rawh = (char *) *prompt_p; + for (i = PAM_BP_MIN_SIZE; i<size; ++i) { + if (rawh[i] == '/') { + break; + } + } + + if ( (i >= size) + || !__pamc_valid_agent_id(i-PAM_BP_MIN_SIZE, + rawh + PAM_BP_MIN_SIZE) ) { + goto pamc_unknown_prompt; + } + + rawh[i] = '\0'; + retval = pamc_load(pch, PAM_BP_MIN_SIZE + rawh); + if (retval == PAM_BPC_TRUE) { + retval = __pamc_select_agent(pch, PAM_BP_MIN_SIZE + rawh); + } + rawh[i] = '/'; + + if (retval != PAM_BPC_TRUE) { + goto pamc_unknown_prompt; + } + + D(("agent is loaded")); + } + + if (pch->current == NULL) { + D(("unable to address agent")); + goto pamc_unknown_prompt; + } + + /* pump all of the prompt into the agent */ + do { + int rval = write(pch->current->writer, + offset + (const __u8 *) (*prompt_p), + size - offset); + if (rval == -1) { + switch (errno) { + case EINTR: + break; + default: + D(("problem writing to agent: %s", strerror(errno))); + goto pamc_unknown_prompt; + } + } else { + offset += rval; + } + } while (offset < size); + + D(("whole prompt sent to agent")); + + /* read size and control for response prompt */ + + offset = 0; + memset(raw, 0, sizeof(raw)); + do { + int rval; + + rval = read(pch->current->reader, raw + offset, + PAM_BP_MIN_SIZE - offset); + + if (rval == -1) { + switch (errno) { + case EINTR: + break; + default: + D(("problem reading from agent: %s", strerror(errno))); + goto pamc_unknown_prompt; + } + } else if (rval) { + offset += rval; + } else { + D(("agent has closed its output pipe - nothing more to read")); + goto pamc_converse_failure; + } + } while (offset < PAM_BP_MIN_SIZE); + + /* construct the whole reply prompt */ + + size = PAM_BP_SIZE(raw); + control = PAM_BP_RCONTROL(raw); + memset(raw, 0, sizeof(raw)); + + D(("agent replied with prompt of size %d and control %u", + size, control)); + + PAM_BP_RENEW(prompt_p, control, size - PAM_BP_MIN_SIZE); + if (*prompt_p == NULL) { + D(("problem making a new prompt for reply")); + goto pamc_unknown_prompt; + } + + /* read the rest of the reply prompt -- note offset has the correct + value from the previous loop */ + + while (offset < size) { + int rval = read(pch->current->reader, offset + (__u8 *) *prompt_p, + size-offset); + + if (rval == -1) { + switch (errno) { + case EINTR: + break; + default: + D(("problem reading from agent: %s", strerror(errno))); + goto pamc_unknown_prompt; + } + } else if (rval) { + offset += rval; + } else { + D(("problem reading prompt (%d) with %d to go", + size, size-offset)); + goto pamc_converse_failure; + } + } + + D(("returning success")); + + return PAM_BPC_TRUE; + +pamc_converse_failure: + + D(("conversation failure")); + PAM_BP_RENEW(prompt_p, 0, 0); + return PAM_BPC_FALSE; + +pamc_unknown_prompt: + + /* the server is trying something that the client does not support */ + D(("unknown prompt")); + PAM_BP_RENEW(prompt_p, PAM_BPC_FAIL, 0); + return PAM_BPC_TRUE; +} + diff --git a/Linux-PAM/libpamc/pamc_load.c b/Linux-PAM/libpamc/pamc_load.c new file mode 100644 index 00000000..2e044eb9 --- /dev/null +++ b/Linux-PAM/libpamc/pamc_load.c @@ -0,0 +1,477 @@ +/* + * $Id: pamc_load.c,v 1.1.1.1 2001/04/29 04:17:13 hartmans Exp $ + * + * Copyright (c) 1999 Andrew G. Morgan <morgan@ftp.kernel.org> + * + * pamc_load + */ + +#include "libpamc.h" + +static int __pamc_exec_agent(pamc_handle_t pch, pamc_agent_t *agent) +{ + char *full_path; + int found_agent, length, reset_length, to_agent[2], from_agent[2]; + int return_code = PAM_BPC_FAIL; + + if (agent->id[agent->id_length] != '\0') { + PAM_BP_ASSERT("libpamc: internal error agent_id not terminated"); + } + + for (length=0; (length < agent->id_length); ++length) { + switch (agent->id[length]) { + case '/': + D(("ill formed agent id")); + return PAM_BPC_FAIL; + } + } + + /* enough memory for any path + this agent */ + reset_length = 3 + pch->max_path + agent->id_length; + D(("reset_length = %d (3+%d+%d)", + reset_length, pch->max_path, agent->id_length)); + full_path = malloc(reset_length); + if (full_path == NULL) { + D(("no memory for agent path")); + return PAM_BPC_FAIL; + } + + found_agent = 0; + for (length=0; pch->agent_paths[length]; ++length) { + struct stat buf; + + D(("path: [%s]", pch->agent_paths[length])); + D(("agent id: [%s]", agent->id)); + + sprintf(full_path, "%s/%s", pch->agent_paths[length], agent->id); + + D(("looking for agent here: [%s]\n", full_path)); + if (stat(full_path, &buf) == 0) { + D(("file existis")); + found_agent = 1; + break; + } + } + + if (! found_agent) { + D(("no agent was found")); + goto free_and_return; + } + + if (pipe(to_agent)) { + D(("failed to open pipe to agent")); + goto free_and_return; + } + + if (pipe(from_agent)) { + D(("failed to open pipe from agent")); + goto close_the_agent; + } + + agent->pid = fork(); + if (agent->pid == -1) { + + D(("failed to fork for agent")); + goto close_both_pipes; + + } else if (agent->pid == 0) { + + int i; + + dup2(from_agent[1], STDOUT_FILENO); + dup2(to_agent[0], STDIN_FILENO); + + /* we close all of the files that have filedescriptors lower + and equal to twice the highest we have seen, The idea is + that we don't want to leak filedescriptors to agents from a + privileged client application. + + XXX - this is a heuristic at this point. There is a growing + need for an extra 'set param' libpamc function, that could + be used to supply info like the highest fd to close etc.. + */ + + if (from_agent[1] > pch->highest_fd_to_close) { + pch->highest_fd_to_close = 2*from_agent[1]; + } + + for (i=0; i <= pch->highest_fd_to_close; ++i) { + switch (i) { + case STDOUT_FILENO: + case STDERR_FILENO: + case STDIN_FILENO: + /* only these three remain open */ + break; + default: + (void) close(i); /* don't care if its not open */ + } + } + + /* we make no attempt to drop other privileges - this library + has no idea how that would be done in the general case. It + is up to the client application (when calling + pamc_converse) to make sure no privilege will leak into an + (untrusted) agent. */ + + /* we propogate no environment - future versions of this + library may have the ability to audit all agent + transactions. */ + + D(("exec'ing agent %s", full_path)); + execle(full_path, "pam-agent", NULL, NULL); + + D(("exec failed")); + exit(1); + + } + + close(to_agent[0]); + close(from_agent[1]); + + agent->writer = to_agent[1]; + agent->reader = from_agent[0]; + + return_code = PAM_BPC_TRUE; + goto free_and_return; + +close_both_pipes: + close(from_agent[0]); + close(from_agent[1]); + +close_the_agent: + close(to_agent[0]); + close(to_agent[1]); + +free_and_return: + memset(full_path, 0, reset_length); + free(full_path); + + D(("returning %d", return_code)); + + return return_code; +} + +/* + * has the named agent been loaded? + */ + +static int __pamc_agent_is_enabled(pamc_handle_t pch, const char *agent_id) +{ + pamc_agent_t *agent; + + for (agent = pch->chain; agent; agent = agent->next) { + if (!strcmp(agent->id, agent_id)) { + D(("agent already loaded")); + return PAM_BPC_TRUE; + } + } + + D(("agent is not loaded")); + return PAM_BPC_FALSE; +} + +/* + * has the named agent been disabled? + */ + +static int __pamc_agent_is_disabled(pamc_handle_t pch, const char *agent_id) +{ + pamc_blocked_t *blocked; + + for (blocked=pch->blocked_agents; blocked; blocked = blocked->next) { + if (!strcmp(agent_id, blocked->id)) { + D(("agent is disabled")); + return PAM_BPC_TRUE; + } + } + + D(("agent is not disabled")); + return PAM_BPC_FALSE; +} + +/* + * disable an agent + */ + +int pamc_disable(pamc_handle_t pch, const char *agent_id) +{ + pamc_blocked_t *block; + + if (pch == NULL) { + D(("pch is NULL")); + return PAM_BPC_FALSE; + } + + if (agent_id == NULL) { + D(("agent_id is NULL")); + return PAM_BPC_FALSE; + } + + if (__pamc_agent_is_enabled(pch, agent_id) != PAM_BPC_FALSE) { + D(("agent is already loaded")); + return PAM_BPC_FALSE; + } + + if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) { + D(("agent is already disabled")); + return PAM_BPC_TRUE; + } + + block = calloc(1, sizeof(pamc_blocked_t)); + if (block == NULL) { + D(("no memory for new blocking structure")); + return PAM_BPC_FALSE; + } + + block->id = malloc(1 + strlen(agent_id)); + if (block->id == NULL) { + D(("no memory for agent id")); + free(block); + return PAM_BPC_FALSE; + } + + strcpy(block->id, agent_id); + block->next = pch->blocked_agents; + pch->blocked_agents = block; + + return PAM_BPC_TRUE; +} + +/* + * force the loading of a particular agent + */ + +int pamc_load(pamc_handle_t pch, const char *agent_id) +{ + pamc_agent_t *agent; + int length; + + /* santity checking */ + + if (pch == NULL) { + D(("pch is NULL")); + return PAM_BPC_FALSE; + } + + if (agent_id == NULL) { + D(("agent_id is NULL")); + return PAM_BPC_FALSE; + } + + if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) { + D(("sorry agent is disabled")); + return PAM_BPC_FALSE; + } + + length = strlen(agent_id); + + /* scan list to see if agent is loaded */ + + if (__pamc_agent_is_enabled(pch, agent_id) == PAM_BPC_TRUE) { + D(("no need to load an already loaded agent (%s)", agent_id)); + return PAM_BPC_TRUE; + } + + /* not in the list, so we need to load it and add it to the head + of the chain */ + + agent = calloc(1, sizeof(pamc_agent_t)); + if (agent == NULL) { + D(("no memory for new agent")); + return PAM_BPC_FALSE; + } + agent->id = calloc(1, 1+length); + if (agent->id == NULL) { + D(("no memory for new agent's id")); + goto fail_free_agent; + } + memcpy(agent->id, agent_id, length); + agent->id[length] = '\0'; + agent->id_length = length; + + if (__pamc_exec_agent(pch, agent) != PAM_BPC_TRUE) { + D(("unable to exec agent")); + goto fail_free_agent_id; + } + + agent->next = pch->chain; + pch->chain = agent; + + return PAM_BPC_TRUE; + +fail_free_agent_id: + + memset(agent->id, 0, agent->id_length); + free(agent->id); + + memset(agent, 0, sizeof(*agent)); + +fail_free_agent: + + free(agent); + return PAM_BPC_FALSE; +} + +/* + * what's a valid agent name? + */ + +int __pamc_valid_agent_id(int id_length, const char *id) +{ + int post, i; + + for (i=post=0 ; i < id_length; ++i) { + int ch = id[i++]; + + if (isalpha(ch) || isdigit(ch) || (ch == '_')) { + continue; + } else if (post && (ch == '.')) { + continue; + } else if ((i > 1) && (!post) && (ch == '@')) { + post = 1; + } else { + D(("id=%s contains '%c' which is illegal", id, ch)); + return 0; + } + } + + if (!i) { + D(("length of id is 0")); + return 0; + } else { + return 1; /* id is valid */ + } +} + +/* + * building a tree of available agent names + */ + +static pamc_id_node_t *__pamc_add_node(pamc_id_node_t *root, const char *id, + int *counter) +{ + if (root) { + + int cmp; + + if ((cmp = strcmp(id, root->agent_id))) { + if (cmp > 0) { + root->right = __pamc_add_node(root->right, id, + &(root->child_count)); + } else { + root->left = __pamc_add_node(root->left, id, + &(root->child_count)); + } + } + + return root; + + } else { + + pamc_id_node_t *node = calloc(1, sizeof(pamc_id_node_t)); + + if (node) { + node->agent_id = malloc(1+strlen(id)); + if (node->agent_id) { + strcpy(node->agent_id, id); + } else { + free(node); + node = NULL; + } + } + + (*counter)++; + return node; + } +} + +/* + * drop all of the tree and any remaining ids + */ + +static pamc_id_node_t *__pamc_liberate_nodes(pamc_id_node_t *tree) +{ + if (tree) { + if (tree->agent_id) { + free(tree->agent_id); + tree->agent_id = NULL; + } + + tree->left = __pamc_liberate_nodes(tree->left); + tree->right = __pamc_liberate_nodes(tree->right); + + tree->child_count = 0; + free(tree); + } + + return NULL; +} + +/* + * fill a list with the contents of the tree (in ascii order) + */ + +static void __pamc_fill_list_from_tree(pamc_id_node_t *tree, char **agent_list, + int *counter) +{ + if (tree) { + __pamc_fill_list_from_tree(tree->left, agent_list, counter); + agent_list[(*counter)++] = tree->agent_id; + tree->agent_id = NULL; + __pamc_fill_list_from_tree(tree->right, agent_list, counter); + } +} + +/* + * get a list of the available agents + */ + +char **pamc_list_agents(pamc_handle_t pch) +{ + int i, total_agent_count=0; + pamc_id_node_t *tree = NULL; + char **agent_list; + + /* loop over agent paths */ + + for (i=0; pch->agent_paths[i]; ++i) { + DIR *dir; + + dir = opendir(pch->agent_paths[i]); + if (dir) { + struct dirent *item; + + while ((item = readdir(dir))) { + + /* this is a cheat on recognizing agent_ids */ + if (!__pamc_valid_agent_id(strlen(item->d_name), + item->d_name)) { + continue; + } + + tree = __pamc_add_node(tree, item->d_name, &total_agent_count); + } + + closedir(dir); + } + } + + /* now, we build a list of ids */ + D(("total of %d available agents\n", total_agent_count)); + + agent_list = calloc(total_agent_count+1, sizeof(char *)); + if (agent_list) { + int counter=0; + + __pamc_fill_list_from_tree(tree, agent_list, &counter); + if (counter != total_agent_count) { + PAM_BP_ASSERT("libpamc: internal error transcribing tree"); + } + } else { + D(("no memory for agent list")); + } + + __pamc_liberate_nodes(tree); + + return agent_list; +} diff --git a/Linux-PAM/libpamc/test/agents/secret@here b/Linux-PAM/libpamc/test/agents/secret@here new file mode 100755 index 00000000..afdcbaa8 --- /dev/null +++ b/Linux-PAM/libpamc/test/agents/secret@here @@ -0,0 +1,308 @@ +#!/usr/bin/perl +# +# This is a simple example PAM authentication agent, it implements a +# simple shared secret authentication scheme. The PAM module pam_secret.so +# is its counter part. Both the agent and the remote server are able to +# authenticate one another, but the server is given the opportunity to +# ignore a failed authentication. +# + +$^W = 1; +use strict; +use IPC::Open2; +$| = 1; + +# display extra information to STDERR +my $debug = 0; +if (scalar @ARGV) { + $debug = 1; +} + +# Globals + +my %state; +my $default_key; + +my $next_key = $$; + +# loop over binary prompts +for (;;) { + my ($control, $data) = ReadBinaryPrompt(); + my ($reply_control, $reply_data); + + if ($control == 0) { + if ($debug) { + print STDERR "agent: no packet to read\n"; + } + last; + } elsif ($control == 0x02) { + ($reply_control, $reply_data) = HandleAgentSelection($data); + } elsif ($control == 0x01) { + ($reply_control, $reply_data) = HandleContinuation($data); + } else { + if ($debug) { + print STDERR + "agent: unrecognized packet $control {$data} to read\n"; + } + ($reply_control, $reply_data) = (0x04, ""); + } + + WriteBinaryPrompt($reply_control, $reply_data); +} + +# Only willing to exit well if we've completed our authentication exchange + +if (scalar keys %state) { + if ($debug) { + print STDERR "The following sessions are still active:\n "; + print STDERR join ', ', keys %state; + print STDERR "\n"; + } + exit 1; +} else { + exit 0; +} + +sub HandleAgentSelection ($) { + my ($data) = @_; + + unless ( $data =~ /^([a-zA-Z0-9_]+\@?[a-zA-Z0-9_.]*)\/(.*)$/ ) { + return (0x04, ""); + } + + my ($agent_name, $payload) = ($1, $2); + if ($debug) { + print STDERR "agent: ". "agent=$agent_name, payload=$payload\n"; + } + + # this agent has a defined name + if ($agent_name ne "secret\@here") { + if ($debug) { + print STDERR "bad agent name: [$agent_name]\n"; + } + return (0x04, ""); + } + + # the selection request is acompanied with a hexadecimal cookie + my @tokens = split '\|', $payload; + + unless ((scalar @tokens) == 2) { + if ($debug) { + print STDERR "bad payload\n"; + } + return (0x04, ""); + } + + unless ($tokens[1] =~ /^[a-z0-9]+$/) { + if ($debug) { + print STDERR "bad server cookie\n"; + } + return (0x04, ""); + } + + my $shared_secret = IdentifyLocalSecret($tokens[0]); + + unless (defined $shared_secret) { + # make a secret up + if ($debug) { + print STDERR "agent: cannot authenticate user\n"; + } + $shared_secret = GetRandom(); + } + + my $local_cookie = GetRandom(); + $default_key = $next_key++; + + $state{$default_key} = $local_cookie ."|". $tokens[1] ."|". $shared_secret; + + if ($debug) { + print STDERR "agent: \$state{$default_key} = $state{$default_key}\n"; + } + + return (0x01, $default_key ."|". $local_cookie); +} + +sub HandleContinuation ($) { + my ($data) = @_; + + my ($key, $server_digest) = split '\|', $data; + + unless (defined $state{$key}) { + # retries and out of sequence prompts are not permitted + return (0x04, ""); + } + + my $expected_digest = CreateDigest($state{$key}); + my ($local_cookie, $remote_cookie, $shared_secret) + = split '\|', $state{$key}; + delete $state{$key}; + + unless ($expected_digest eq $server_digest) { + if ($debug) { + print STDERR "agent: don't trust server - faking reply\n"; + print STDERR "agent: got ($server_digest)\n"; + print STDERR "agent: expected ($expected_digest)\n"; + } + + ## FIXME: Agent should exchange a prompt with the client warning + ## that the server is faking us out. + + return (0x03, CreateDigest($expected_digest . $data . GetRandom())); + } + + if ($debug) { + print STDERR "agent: server appears to know the secret\n"; + } + + my $session_authenticated_ticket = + CreateDigest($remote_cookie."|".$shared_secret."|".$local_cookie); + + # FIXME: Agent should set a derived session key environment + # variable (available for the client (and its children) to sign + # future data exchanges. + + if ($debug) { + print STDERR "agent: should putenv(" + ."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n"; + } + + # return agent's authenticating digest + return (0x03, CreateDigest($shared_secret."|".$remote_cookie + ."|".$local_cookie)); +} + +sub ReadBinaryPrompt { + my $buffer = " "; + my $count = read(STDIN, $buffer, 5); + if ($count == 0) { + # no more packets to read + return (0, ""); + } + + if ($count != 5) { + # broken packet header + return (-1, ""); + } + + my ($length, $control) = unpack("N C", $buffer); + if ($length < 5) { + # broken packet length + return (-1, ""); + } + + my $data = ""; + $length -= 5; + while ($count = read(STDIN, $buffer, $length)) { + $data .= $buffer; + if ($count != $length) { + $length -= $count; + next; + } + + if ($debug) { + print STDERR "agent: ". "data is [$data]\n"; + } + + return ($control, $data); + } + + # broken packet data + return (-1, ""); +} + +sub WriteBinaryPrompt ($$) { + my ($control, $data) = @_; + + my $length = 5 + length($data); + if ($debug) { + printf STDERR "agent: ". "{%d|0x%.2x|%s}\n", $length, $control, $data; + } + my $bp = pack("N C a*", $length, $control, $data); + print STDOUT $bp; + if ($debug) { + printf STDERR "agent: ". "agent has replied\n"; + } +} + +## +## Here is where we parse the simple secret file +## The format of this file is a list of lines of the following form: +## +## user@client0.host.name secret_string1 +## user@client1.host.name secret_string2 +## user@client2.host.name secret_string3 +## + +sub IdentifyLocalSecret ($) { + my ($identifier) = @_; + my $secret; + + if (open SECRETS, "< ". (getpwuid($<))[7] ."/.secret\@here") { + my $line; + while (defined ($line = <SECRETS>)) { + my ($id, $sec) = split /[\s]+/, $line; + if ((defined $id) && ($id eq $identifier)) { + $secret = $sec; + last; + } + } + close SECRETS; + } + + return $secret; +} + +## Here is where we generate a message digest + +sub CreateDigest ($) { + my ($data) = @_; + + my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -") + or die "you'll need /usr/bin/md5sum installed"; + + my $oldfd = select MD5in; $|=1; select $oldfd; + if ($debug) { + print STDERR "agent: ". "telling md5: <$data>\n"; + } + print MD5in "$data"; + close MD5in; + my $reply = <MD5out>; + ($reply) = split /\s/, $reply; + if ($debug) { + print STDERR "agent: ". "md5 said: <$reply>\n"; + } + close MD5out; + + return $reply; +} + +## get a random number + +sub GetRandom { + + if ( -r "/dev/urandom" ) { + open RANDOM, "< /dev/urandom" or die "crazy"; + + my $i; + my $reply = ""; + + for ($i=0; $i<4; ++$i) { + my $buffer = " "; + while (read(RANDOM, $buffer, 4) != 4) { + ; + } + $reply .= sprintf "%.8x", unpack("N", $buffer); + if ($debug) { + print STDERR "growing reply: [$reply]\n"; + } + } + close RANDOM; + + return $reply; + } else { + print STDERR "agent: ". "[got linux?]\n"; + return "%.8x%.8x%.8x%.8x", time, time, time, time; + } + +} + diff --git a/Linux-PAM/libpamc/test/modules/Makefile b/Linux-PAM/libpamc/test/modules/Makefile new file mode 100644 index 00000000..48065462 --- /dev/null +++ b/Linux-PAM/libpamc/test/modules/Makefile @@ -0,0 +1,9 @@ +CFLAGS = -g -fPIC -I"../../include" + +pam_secret.so: pam_secret.o + ld -x --shared -o pam_secret.so pam_secret.o -lc + +.o.c: + +clean: + rm -f *.so *.o diff --git a/Linux-PAM/libpamc/test/modules/pam_secret.c b/Linux-PAM/libpamc/test/modules/pam_secret.c new file mode 100644 index 00000000..557f5959 --- /dev/null +++ b/Linux-PAM/libpamc/test/modules/pam_secret.c @@ -0,0 +1,670 @@ +/* + * $Id: pam_secret.c,v 1.1.1.1 2001/04/29 04:17:14 hartmans Exp $ + * + * Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org> + */ + +/* + * WARNING: AS WRITTEN THIS CODE IS NOT SECURE. THE MD5 IMPLEMENTATION + * NEEDS TO BE INTEGRATED MORE NATIVELY. + */ + +/* #define DEBUG */ + +#include <fcntl.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <security/pam_modules.h> +#include <security/pam_client.h> +#include <security/_pam_macros.h> + +/* + * This is a sample module that demonstrates the use of binary prompts + * and how they can be used to implement sophisticated authentication + * schemes. + */ + +struct ps_state_s { + int retval; /* last retval returned by the authentication fn */ + int state; /* what state the module was in when it + returned incomplete */ + + char *username; /* the name of the local user */ + + char server_cookie[33]; /* storage for 32 bytes of server cookie */ + char client_cookie[33]; /* storage for 32 bytes of client cookie */ + + char *secret_data; /* pointer to <NUL> terminated secret_data */ + int invalid_secret; /* indication of whether the secret is valid */ + + pamc_bp_t current_prompt; /* place to store the current prompt */ + pamc_bp_t current_reply; /* place to receive the reply prompt */ +}; + +#define PS_STATE_ID "PAM_SECRET__STATE" +#define PS_AGENT_ID "secret@here" +#define PS_STATE_DEAD 0 +#define PS_STATE_INIT 1 +#define PS_STATE_PROMPT1 2 +#define PS_STATE_PROMPT2 3 + +#define MAX_LEN_HOSTNAME 512 +#define MAX_FILE_LINE_LEN 1024 + +/* + * Routine for generating 16*8 bits of random data represented in ASCII hex + */ + +static int generate_cookie(unsigned char *buffer_33) +{ + static const char hexarray[] = "0123456789abcdef"; + int i, fd; + + /* fill buffer_33 with 32 hex characters (lower case) + '\0' */ + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + D(("failed to open /dev/urandom")); + return 0; + } + read(fd, buffer_33 + 16, 16); + close(fd); + + /* expand top 16 bytes into 32 nibbles */ + for (i=0; i<16; ++i) { + buffer_33[2*i ] = hexarray[(buffer_33[16+i] & 0xf0)>>4]; + buffer_33[2*i+1] = hexarray[(buffer_33[16+i] & 0x0f)]; + } + + buffer_33[32] = '\0'; + + return 1; +} + +/* + * XXX - This is a hack, and is fundamentally insecure. Its subject to + * all sorts of attacks not to mention the fact that all our secrets + * will be displayed on the command line for someone doing 'ps' to + * see. This is just for programming convenience in this instance, it + * needs to be replaced with the md5 code. Although I am loath to + * add yet another instance of md5 code to the Linux-PAM source code. + * [Need to think of a cleaner way to do this for the distribution as + * a whole...] + */ + +#define COMMAND_FORMAT "/bin/echo -n '%s|%s|%s'|/usr/bin/md5sum -" + +int create_digest(const char *d1, const char *d2, const char *d3, + char *buffer_33) +{ + int length; + char *buffer; + FILE *pipe; + + length = strlen(d1)+strlen(d2)+strlen(d3)+sizeof(COMMAND_FORMAT); + buffer = malloc(length); + if (buffer == NULL) { + D(("out of memory")); + return 0; + } + + sprintf(buffer, COMMAND_FORMAT, d1,d2,d3); + + D(("executing pipe [%s]", buffer)); + pipe = popen(buffer, "r"); + memset(buffer, 0, length); + free(buffer); + + if (pipe == NULL) { + D(("failed to launch pipe")); + return 0; + } + + if (fgets(buffer_33, 33, pipe) == NULL) { + D(("failed to read digest")); + return 0; + } + + if (strlen(buffer_33) != 32) { + D(("digest was not 32 chars")); + return 0; + } + + fclose(pipe); + + D(("done [%s]", buffer_33)); + + return 1; +} + +/* + * method to attempt to instruct the application's conversation function + */ + +static int converse(pam_handle_t *pamh, struct ps_state_s *new) +{ + int retval; + struct pam_conv *conv; + + D(("called")); + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (retval == PAM_SUCCESS) { + struct pam_message msg; + struct pam_response *single_reply; + const struct pam_message *msg_ptr; + + memset(&msg, 0, sizeof(msg)); + msg.msg_style = PAM_BINARY_PROMPT; + msg.msg = (const char *) new->current_prompt; + msg_ptr = &msg; + + single_reply = NULL; + retval = conv->conv(1, &msg_ptr, &single_reply, conv->appdata_ptr); + if (retval == PAM_SUCCESS) { + if ((single_reply == NULL) || (single_reply->resp == NULL)) { + retval == PAM_CONV_ERR; + } else { + new->current_reply = (pamc_bp_t) single_reply->resp; + single_reply->resp = NULL; + } + } + + if (single_reply) { + free(single_reply); + } + } + +#ifdef DEBUG + if (retval == PAM_SUCCESS) { + D(("reply has length=%d and control=%u", + PAM_BP_LENGTH(new->current_reply), + PAM_BP_CONTROL(new->current_reply))); + } + D(("returning %s", pam_strerror(pamh, retval))); +#endif + + return retval; +} + +/* + * identify the secret in question + */ + +#define SECRET_FILE_FORMAT "%s/.secret@here" + +char *identify_secret(char *identity, const char *user) +{ + struct passwd *pwd; + char *temp; + FILE *secrets; + int length_id; + + pwd = getpwnam(user); + if ((pwd == NULL) || (pwd->pw_dir == NULL)) { + D(("user [%s] is not known", user)); + } + + length_id = strlen(pwd->pw_dir) + sizeof(SECRET_FILE_FORMAT); + temp = malloc(length_id); + if (temp == NULL) { + D(("out of memory")); + pwd = NULL; + return NULL; + } + + sprintf(temp, SECRET_FILE_FORMAT, pwd->pw_dir); + pwd = NULL; + + D(("opening key file [%s]", temp)); + secrets = fopen(temp, "r"); + memset(temp, 0, length_id); + + if (secrets == NULL) { + D(("failed to open key file")); + return NULL; + } + + length_id = strlen(identity); + temp = malloc(MAX_FILE_LINE_LEN); + + for (;;) { + char *secret = NULL; + + if (fgets(temp, MAX_FILE_LINE_LEN, secrets) == NULL) { + fclose(secrets); + return NULL; + } + + D(("cf[%s][%s]", identity, temp)); + if (memcmp(temp, identity, length_id)) { + continue; + } + + D(("found entry")); + fclose(secrets); + + for (secret=temp+length_id; *secret; ++secret) { + if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) { + break; + } + } + + memmove(temp, secret, MAX_FILE_LINE_LEN-(secret-(temp+length_id))); + secret = temp; + + for (; *secret; ++secret) { + if (*secret == ' ' || *secret == '\n' || *secret == '\t') { + break; + } + } + + if (*secret) { + *secret = '\0'; + } + + D(("secret found [%s]", temp)); + + return temp; + } + + /* NOT REACHED */ +} + +/* + * function to perform the two message authentication process + * (with support for event driven conversation functions) + */ + +static int auth_sequence(pam_handle_t *pamh, + const struct ps_state_s *old, struct ps_state_s *new) +{ + const char *rhostname; + const char *rusername; + int retval; + + retval = pam_get_item(pamh, PAM_RUSER, (const void **) &rusername); + if ((retval != PAM_SUCCESS) || (rusername == NULL)) { + D(("failed to obtain an rusername")); + new->state = PS_STATE_DEAD; + return PAM_AUTH_ERR; + } + + retval = pam_get_item(pamh, PAM_RHOST, (const void **) &rhostname); + if ((retval != PAM_SUCCESS) || (rhostname == NULL)) { + D(("failed to identify local hostname: ", pam_strerror(pamh, retval))); + new->state = PS_STATE_DEAD; + return PAM_AUTH_ERR; + } + + D(("switch on new->state=%d [%s@%s]", new->state, rusername, rhostname)); + switch (new->state) { + + case PS_STATE_INIT: + { + const char *user = NULL; + + retval = pam_get_user(pamh, &user, NULL); + + if ((retval == PAM_SUCCESS) && (user == NULL)) { + D(("success but no username?")); + new->state = PS_STATE_DEAD; + retval = PAM_USER_UNKNOWN; + } + + if (retval != PAM_SUCCESS) { + if (retval == PAM_CONV_AGAIN) { + retval = PAM_INCOMPLETE; + } else { + new->state = PS_STATE_DEAD; + } + D(("state init failed: %s", pam_strerror(pamh, retval))); + return retval; + } + + /* nothing else in this 'case' can be retried */ + + new->username = strdup(user); + if (new->username == NULL) { + D(("out of memory")); + new->state = PS_STATE_DEAD; + return PAM_BUF_ERR; + } + + if (! generate_cookie(new->server_cookie)) { + D(("problem generating server cookie")); + new->state = PS_STATE_DEAD; + return PAM_ABORT; + } + + new->current_prompt = NULL; + PAM_BP_RENEW(&new->current_prompt, PAM_BPC_SELECT, + sizeof(PS_AGENT_ID) + strlen(rusername) + 1 + + strlen(rhostname) + 1 + 32); + sprintf(PAM_BP_WDATA(new->current_prompt), + PS_AGENT_ID "/%s@%s|%.32s", rusername, rhostname, + new->server_cookie); + + /* note, the BP is guaranteed by the spec to be <NUL> terminated */ + D(("initialization packet [%s]", PAM_BP_DATA(new->current_prompt))); + + /* fall through */ + new->state = PS_STATE_PROMPT1; + + D(("fall through to state_prompt1")); + } + + case PS_STATE_PROMPT1: + { + int i, length; + + /* send {secret@here/jdoe@client.host|<s_cookie>} */ + retval = converse(pamh, new); + if (retval != PAM_SUCCESS) { + if (retval == PAM_CONV_AGAIN) { + D(("conversation failed to complete")); + return PAM_INCOMPLETE; + } else { + new->state = PS_STATE_DEAD; + return retval; + } + } + + if (retval != PAM_SUCCESS) { + D(("failed to read ruser@rhost")); + new->state = PS_STATE_DEAD; + return PAM_AUTH_ERR; + } + + /* expect to receive the following {<seqid>|<a_cookie>} */ + if (new->current_reply == NULL) { + D(("converstation returned [%s] but gave no reply", + pam_strerror(pamh, retval))); + new->state = PS_STATE_DEAD; + return PAM_CONV_ERR; + } + + /* find | */ + length = PAM_BP_LENGTH(new->current_reply); + for (i=0; i<length; ++i) { + if (PAM_BP_RDATA(new->current_reply)[i] == '|') { + break; + } + } + if (i >= length) { + D(("malformed response (no |) of length %d", length)); + new->state = PS_STATE_DEAD; + return PAM_CONV_ERR; + } + if ((length - ++i) != 32) { + D(("cookie is incorrect length (%d,%d) %d != 32", + length, i, length-i)); + new->state = PS_STATE_DEAD; + return PAM_CONV_ERR; + } + + /* copy client cookie */ + memcpy(new->client_cookie, PAM_BP_RDATA(new->current_reply)+i, 32); + + /* generate a prompt that is length(seqid) + length(|) + 32 long */ + PAM_BP_RENEW(&new->current_prompt, PAM_BPC_OK, i+32); + /* copy the head of the response prompt */ + memcpy(PAM_BP_WDATA(new->current_prompt), + PAM_BP_RDATA(new->current_reply), i); + PAM_BP_RENEW(&new->current_reply, 0, 0); + + /* look up the secret */ + new->invalid_secret = 0; + + if (new->secret_data == NULL) { + char *ruser_rhost; + + ruser_rhost = malloc(strlen(rusername)+2+strlen(rhostname)); + if (ruser_rhost == NULL) { + D(("out of memory")); + new->state = PS_STATE_DEAD; + return PAM_BUF_ERR; + } + sprintf(ruser_rhost, "%s@%s", rusername, rhostname); + new->secret_data = identify_secret(ruser_rhost, new->username); + + memset(ruser_rhost, 0, strlen(ruser_rhost)); + free(ruser_rhost); + } + + if (new->secret_data == NULL) { + D(("secret not found for user")); + new->invalid_secret = 1; + + /* need to make up a secret */ + new->secret_data = malloc(32 + 1); + if (new->secret_data == NULL) { + D(("out of memory")); + new->state = PS_STATE_DEAD; + return PAM_BUF_ERR; + } + if (! generate_cookie(new->secret_data)) { + D(("what's up - no fake cookie generated?")); + new->state = PS_STATE_DEAD; + return PAM_ABORT; + } + } + + /* construct md5[<client_cookie>|<server_cookie>|<secret_data>] */ + if (! create_digest(new->client_cookie, new->server_cookie, + new->secret_data, + PAM_BP_WDATA(new->current_prompt)+i)) { + D(("md5 digesting failed")); + new->state = PS_STATE_DEAD; + return PAM_ABORT; + } + + /* prompt2 is now constructed - fall through to send it */ + } + + case PS_STATE_PROMPT2: + { + /* send {<seqid>|md5[<client_cookie>|<server_cookie>|<secret_data>]} */ + retval = converse(pamh, new); + if (retval != PAM_SUCCESS) { + if (retval == PAM_CONV_AGAIN) { + D(("conversation failed to complete")); + return PAM_INCOMPLETE; + } else { + new->state = PS_STATE_DEAD; + return retval; + } + } + + /* After we complete this section, we should not be able to + recall this authentication function. So, we force all + future calls into the weeds. */ + + new->state = PS_STATE_DEAD; + + /* expect reply:{md5[<secret_data>|<server_cookie>|<client_cookie>]} */ + + { + int cf; + char expectation[33]; + + if (!create_digest(new->secret_data, new->server_cookie, + new->client_cookie, expectation)) { + new->state = PS_STATE_DEAD; + return PAM_ABORT; + } + + cf = strcmp(expectation, PAM_BP_RDATA(new->current_reply)); + memset(expectation, 0, sizeof(expectation)); + if (cf || new->invalid_secret) { + D(("failed to authenticate")); + return PAM_AUTH_ERR; + } + } + + D(("correctly authenticated :)")); + return PAM_SUCCESS; + } + + default: + new->state = PS_STATE_DEAD; + + case PS_STATE_DEAD: + + D(("state is currently dead/unknown")); + return PAM_AUTH_ERR; + } + + fprintf(stderr, "pam_secret: this should not be reached\n"); + return PAM_ABORT; +} + +static void clean_data(pam_handle_t *pamh, void *datum, int error_status) +{ + struct ps_state_s *data = datum; + + D(("liberating datum=%p", datum)); + + if (data) { + D(("renew prompt")); + PAM_BP_RENEW(&data->current_prompt, 0, 0); + D(("renew reply")); + PAM_BP_RENEW(&data->current_reply, 0, 0); + D(("overwrite datum")); + memset(data, 0, sizeof(struct ps_state_s)); + D(("liberate datum")); + free(data); + } + + D(("done.")); +} + +/* + * front end for the authentication function + */ + +int pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval; + struct ps_state_s *new_data; + const struct ps_state_s *old_data; + + D(("called")); + + new_data = calloc(1, sizeof(struct ps_state_s)); + if (new_data == NULL) { + D(("out of memory")); + return PAM_BUF_ERR; + } + new_data->retval = PAM_SUCCESS; + + retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data); + if (retval == PAM_SUCCESS) { + new_data->state = old_data->state; + memcpy(new_data->server_cookie, old_data->server_cookie, 32); + memcpy(new_data->client_cookie, old_data->client_cookie, 32); + if (old_data->username) { + new_data->username = strdup(old_data->username); + } + if (old_data->secret_data) { + new_data->secret_data = strdup(old_data->secret_data); + } + if (old_data->current_prompt) { + int length; + + length = PAM_BP_LENGTH(old_data->current_prompt); + PAM_BP_RENEW(&new_data->current_prompt, + PAM_BP_CONTROL(old_data->current_prompt), length); + PAM_BP_FILL(new_data->current_prompt, 0, length, + PAM_BP_RDATA(old_data->current_prompt)); + } + /* don't need to duplicate current_reply */ + } else { + old_data = NULL; + new_data->state = PS_STATE_INIT; + } + + D(("call auth_sequence")); + new_data->retval = auth_sequence(pamh, old_data, new_data); + D(("returned from auth_sequence")); + + retval = pam_set_data(pamh, PS_STATE_ID, new_data, clean_data); + if (retval != PAM_SUCCESS) { + D(("unable to store new_data")); + } else { + retval = new_data->retval; + } + + old_data = new_data = NULL; + + D(("done (%d)", retval)); + return retval; +} + +/* + * front end for the credential setting function + */ + +#define AUTH_SESSION_TICKET_ENV_FORMAT "AUTH_SESSION_TICKET=" + +int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval; + const struct ps_state_s *old_data; + + D(("called")); + + /* XXX - need to pay attention to the various flavors of call */ + + /* XXX - need provide an option to turn this feature on/off: if + other modules want to supply an AUTH_SESSION_TICKET, we should + leave it up to the admin which module dominiates. */ + + retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data); + if (retval != PAM_SUCCESS) { + D(("no data to base decision on")); + return PAM_AUTH_ERR; + } + + /* + * If ok, export a derived shared secret session ticket to the + * client's PAM environment - the ticket has the form + * + * AUTH_SESSION_TICKET = + * md5[<server_cookie>|<secret_data>|<client_cookie>] + * + * This is a precursor to supporting a spoof resistant trusted + * path mechanism. This shared secret ticket can be used to add + * a hard-to-guess checksum to further authentication data. + */ + + retval = old_data->retval; + if (retval == PAM_SUCCESS) { + char envticket[sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)+32]; + + memcpy(envticket, AUTH_SESSION_TICKET_ENV_FORMAT, + sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)); + + if (! create_digest(old_data->server_cookie, old_data->secret_data, + old_data->client_cookie, + envticket+sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)-1 + )) { + D(("unable to generate a digest for session ticket")); + return PAM_ABORT; + } + + D(("putenv[%s]", envticket)); + retval = pam_putenv(pamh, envticket); + memset(envticket, 0, sizeof(envticket)); + } + + old_data = NULL; + D(("done (%d)", retval)); + + return retval; +} diff --git a/Linux-PAM/libpamc/test/regress/Makefile b/Linux-PAM/libpamc/test/regress/Makefile new file mode 100644 index 00000000..ff63e5f0 --- /dev/null +++ b/Linux-PAM/libpamc/test/regress/Makefile @@ -0,0 +1,7 @@ +CFLAGS = -g -I ../../include + +test.libpamc: test.libpamc.o + $(CC) -o $@ $< -L ../.. -lpamc + +clean: + rm -f test.libpamc test.libpamc.o diff --git a/Linux-PAM/libpamc/test/regress/run_test.sh b/Linux-PAM/libpamc/test/regress/run_test.sh new file mode 100755 index 00000000..6922f03d --- /dev/null +++ b/Linux-PAM/libpamc/test/regress/run_test.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +LD_LIBRARY_PATH=../.. ; export LD_LIBRARY_PATH +PAMC_AGENT_PATH="../agents" ; export PAMC_AGENT_PATH + +./test.libpamc diff --git a/Linux-PAM/libpamc/test/regress/test.libpamc.c b/Linux-PAM/libpamc/test/regress/test.libpamc.c new file mode 100644 index 00000000..b7bc4e4b --- /dev/null +++ b/Linux-PAM/libpamc/test/regress/test.libpamc.c @@ -0,0 +1,342 @@ +/* + * This is a small test program for testing libpamc against the + * secret@here agent. It does the same as the test.secret@here perl + * script in this directory, but via the libpamc API. + */ + +#include <stdio.h> +#include <string.h> +#include <security/pam_client.h> +#include <ctype.h> + +struct internal_packet { + int length; + int at; + char *buffer; +}; + + +void append_data(struct internal_packet *packet, int extra, const char *data) +{ + if ((extra + packet->at) >= packet->length) { + if (packet->length == 0) { + packet->length = 1000; + } + /* make sure we have at least a char extra space available */ + while (packet->length <= (extra + packet->at)) { + packet->length <<= 1; + } + packet->buffer = realloc(packet->buffer, packet->length); + if (packet->buffer == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + } + + if (data != NULL) { + memcpy(packet->at + packet->buffer, data, extra); + } + packet->at += extra; + + /* assisting string manipulation */ + packet->buffer[packet->at] = '\0'; +} + +void append_string(struct internal_packet *packet, const char *string, + int with_nul) +{ + append_data(packet, strlen(string) + (with_nul ? 1:0), string); +} + +char *identify_secret(char *identity) +{ + struct internal_packet temp_packet; + FILE *secrets; + int length_id; + + temp_packet.length = temp_packet.at = 0; + temp_packet.buffer = NULL; + + append_string(&temp_packet, "/home/", 0); + append_string(&temp_packet, getlogin(), 0); + append_string(&temp_packet, "/.secret@here", 1); + + secrets = fopen(temp_packet.buffer, "r"); + if (secrets == NULL) { + fprintf(stderr, "server: failed to open\n [%s]\n", + temp_packet.buffer); + exit(1); + } + + length_id = strlen(identity); + for (;;) { + char *secret = NULL; + temp_packet.at = 0; + + if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) { + fclose(secrets); + return NULL; + } + + if (memcmp(temp_packet.buffer, identity, length_id)) { + continue; + } + + fclose(secrets); + for (secret=temp_packet.buffer; *secret; ++secret) { + if (*secret == ' ' || *secret == '\n' || *secret == '\t') { + break; + } + } + for (; *secret; ++secret) { + if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) { + break; + } + } + + for (temp_packet.buffer=secret; *temp_packet.buffer; + ++temp_packet.buffer) { + if (*temp_packet.buffer == ' ' || *temp_packet.buffer == '\n' + || *temp_packet.buffer == '\t') { + break; + } + } + if (*temp_packet.buffer) { + *temp_packet.buffer = '\0'; + } + + return secret; + } + + /* NOT REACHED */ +} + +/* + * This is a hack, and is fundamentally insecure. All our secrets will be + * displayed on the command line for someone doing 'ps' to see. This + * is just for programming convenience in this instance, since this + * program is simply a regression test. The pam_secret module should + * not do this, but make use of md5 routines directly. + */ + +char *create_digest(int length, const char *raw) +{ + struct internal_packet temp_packet; + FILE *pipe; + + temp_packet.length = temp_packet.at = 0; + temp_packet.buffer = NULL; + + append_string(&temp_packet, "echo -n '", 0); + append_string(&temp_packet, raw, 0); + append_string(&temp_packet, "'|/usr/bin/md5sum -", 1); + + fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer); + + pipe = popen(temp_packet.buffer, "r"); + if (pipe == NULL) { + fprintf(stderr, "server: failed to run\n [%s]\n", temp_packet.buffer); + exit(1); + } + + temp_packet.at = 0; + append_data(&temp_packet, 32, NULL); + + if (fgets(temp_packet.buffer, 33, pipe) == NULL) { + fprintf(stderr, "server: failed to read digest\n"); + exit(1); + } + if (strlen(temp_packet.buffer) != 32) { + fprintf(stderr, "server: digest was not 32 chars?? [%s]\n", + temp_packet.buffer); + exit(1); + } + + fclose(pipe); + + return temp_packet.buffer; +} + +void packet_to_prompt(pamc_bp_t *prompt_p, __u8 control, + struct internal_packet *packet) +{ + PAM_BP_RENEW(prompt_p, control, packet->at); + PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer); + packet->at = 0; +} + +void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet) +{ + int data_length; + + data_length = PAM_BP_LENGTH(prompt); + packet->at = 0; + append_data(packet, data_length, NULL); + + PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer); + + fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n", + data_length, + PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt), + PAM_BP_RDATA(prompt)); +} + +int main(int argc, char **argv) +{ + pamc_handle_t pch; + pamc_bp_t prompt = NULL; + struct internal_packet packet_data, *packet; + char *temp_string, *secret, *user, *a_cookie, *seqid, *digest; + const char *cookie = "123451234512345"; + int retval; + + packet = &packet_data; + packet->length = 0; + packet->at = 0; + packet->buffer = NULL; + + pch = pamc_start(); + if (pch == NULL) { + fprintf(stderr, "server: unable to get a handle from libpamc\n"); + exit(1); + } + + temp_string = getlogin(); + if (temp_string == NULL) { + fprintf(stderr, "server: who are you?\n"); + exit(1); + } +#define DOMAIN "@local.host" + user = malloc(1+strlen(temp_string)+strlen(DOMAIN)); + if (user == NULL) { + fprintf(stderr, "server: out of memory for user id\n"); + exit(1); + } + sprintf(user, "%s%s", temp_string, DOMAIN); + + append_string(packet, "secret@here/", 0); + append_string(packet, user, 0); + append_string(packet, "|", 0); + append_string(packet, cookie, 0); + packet_to_prompt(&prompt, PAM_BPC_SELECT, packet); + + /* get the library to accept the first packet (which should load + the secret@here agent) */ + + retval = pamc_converse(pch, &prompt); + fprintf(stderr, "server: after conversation\n"); + if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) { + fprintf(stderr, "server: prompt had unexpected control type: %u\n", + PAM_BP_RCONTROL(prompt)); + exit(1); + } + + fprintf(stderr, "server: got a prompt back\n"); + + prompt_to_packet(prompt, packet); + + temp_string = strtok(packet->buffer, "|"); + if (temp_string == NULL) { + fprintf(stderr, "server: prompt does not contain anything"); + exit(1); + } + seqid = strdup(temp_string); + if (seqid == NULL) { + fprintf(stderr, "server: unable to store sequence id\n"); + } + + temp_string = strtok(NULL, "|"); + if (temp_string == NULL) { + fprintf(stderr, "server: no cookie from agent\n"); + exit(1); + } + a_cookie = strdup(temp_string); + if (a_cookie == NULL) { + fprintf(stderr, "server: no memory to store agent cookie\n"); + exit(1); + } + + fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie); + secret = identify_secret(user); + fprintf(stderr, "server: secret=%s\n", secret); + + /* now, we construct the response */ + packet->at = 0; + append_string(packet, a_cookie, 0); + append_string(packet, "|", 0); + append_string(packet, cookie, 0); + append_string(packet, "|", 0); + append_string(packet, secret, 0); + + fprintf(stderr, "server: get digest of %s\n", packet->buffer); + + digest = create_digest(packet->at, packet->buffer); + + fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest); + + packet->at = 0; + append_string(packet, seqid, 0); + append_string(packet, "|", 0); + append_string(packet, digest, 0); + packet_to_prompt(&prompt, PAM_BPC_OK, packet); + + retval = pamc_converse(pch, &prompt); + fprintf(stderr, "server: after 2nd conversation\n"); + if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) { + fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n", + PAM_BP_RCONTROL(prompt)); + exit(1); + } + + prompt_to_packet(prompt, packet); + PAM_BP_RENEW(&prompt, 0, 0); + + temp_string = strtok(packet->buffer, "|"); + if (temp_string == NULL) { + fprintf(stderr, "no digest from agent\n"); + exit(1); + } + temp_string = strdup(temp_string); + + packet->at = 0; + append_string(packet, secret, 0); + append_string(packet, "|", 0); + append_string(packet, cookie, 0); + append_string(packet, "|", 0); + append_string(packet, a_cookie, 0); + + fprintf(stderr, "server: get digest of %s\n", packet->buffer); + + digest = create_digest(packet->at, packet->buffer); + + fprintf(stderr, "server: digest=%s\n", digest); + + if (strcmp(digest, temp_string)) { + fprintf(stderr, "server: agent doesn't know the secret\n"); + fprintf(stderr, "server: agent says: [%s]\n" + "server: server says: [%s]\n", temp_string, digest); + exit(1); + } else { + fprintf(stderr, "server: agent seems to know the secret\n"); + + packet->at = 0; + append_string(packet, cookie, 0); + append_string(packet, "|", 0); + append_string(packet, secret, 0); + append_string(packet, "|", 0); + append_string(packet, a_cookie, 0); + + digest = create_digest(packet->at, packet->buffer); + + fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n", + digest); + } + + + retval = pamc_end(&pch); + + fprintf(stderr, "server: agent(s) were %shappy to terminate\n", + retval == PAM_BPC_TRUE ? "":"un"); + + exit(!retval); +} diff --git a/Linux-PAM/libpamc/test/regress/test.secret@here b/Linux-PAM/libpamc/test/regress/test.secret@here new file mode 100755 index 00000000..2e0b9b94 --- /dev/null +++ b/Linux-PAM/libpamc/test/regress/test.secret@here @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +## +## this is a test script for regressing changes to the secret@here PAM +## agent +## + +$^W = 1; +use strict; +use IPC::Open2; + +$| = 1; + +my $whoami = `/usr/bin/whoami`; chomp $whoami; +my $cookie = "12345"; +my $user_domain = "$whoami\@local.host"; + +my $pid = open2(\*Reader, \*Writer, "../agents/secret\@here blah") + or die "failed to load secret\@here agent"; + +unless (-f (getpwuid($<))[7]."/.secret\@here") { + print STDERR "server: ". "no " .(getpwuid($<))[7]. "/.secret\@here file\n"; + die "no config file"; +} + +WriteBinaryPrompt(\*Writer, 0x02, "secret\@here/$user_domain|$cookie"); + +my ($control, $data) = ReadBinaryPrompt(\*Reader); + +print STDERR "server: ". "reply: control=$control, data=$data\n"; +if ($control != 1) { + die "expected 1 (OK) for the first agent reply; got $control"; +} +my ($seqid, $a_cookie) = split '\|', $data; + +# server needs to convince agent that it knows the secret before +# agent will give a valid response +my $secret = IdentifyLocalSecret($user_domain); +my $digest = CreateDigest($a_cookie."|".$cookie."|".$secret); + +print STDERR "server: ". "digest = $digest\n"; +WriteBinaryPrompt(\*Writer, 0x01, "$seqid|$digest"); + +# The agent will authenticate us and then reply with its +# authenticating digest. we check that before we're done. + +($control, $data) = ReadBinaryPrompt(\*Reader); +if ($control != 0x03) { + die "server: agent did not reply with a 'done' prompt ($control)\n"; +} + +unless ($data eq CreateDigest($secret."|".$cookie."|".$a_cookie)) { + die "server: agent is not authenticated\n"; +} + +print STDERR "server: agent appears to know secret\n"; + +my $session_authenticated_ticket + = CreateDigest($cookie."|".$secret."|".$a_cookie); + +print STDERR "server: should putenv(" + ."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n"; + +exit 0; + +sub CreateDigest ($) { + my ($data) = @_; + + my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -") + or die "you'll need /usr/bin/md5sum installed"; + + my $oldfd = select MD5in; $|=1; select $oldfd; + print MD5in "$data"; + close MD5in; + my $reply = <MD5out>; + ($reply) = split /\s/, $reply; + print STDERR "server: ". "md5 said: <$reply>\n"; + close MD5out; + + return $reply; +} + +sub ReadBinaryPrompt ($) { + my ($fd) = @_; + + my $buffer = " "; + my $count = read($fd, $buffer, 5); + if ($count == 0) { + # no more packets to read + return (0, ""); + } + + if ($count != 5) { + # broken packet header + return (-1, ""); + } + + my ($length, $control) = unpack("N C", $buffer); + if ($length < 5) { + # broken packet length + return (-1, ""); + } + + my $data = ""; + $length -= 5; + while ($count = read($fd, $buffer, $length)) { + $data .= $buffer; + if ($count != $length) { + $length -= $count; + next; + } + + print STDERR "server: ". "data is [$data]\n"; + + return ($control, $data); + } + + # broken packet data + return (-1, ""); +} + +sub WriteBinaryPrompt ($$$) { + my ($fd, $control, $data) = @_; + + my $length = 5 + length($data); + printf STDERR "server: ". "{%d|0x%.2x|%s}\n", $length, $control, $data; + my $bp = pack("N C a*", $length, $control, $data); + print $fd $bp; + + print STDERR "server: ". "control passed to agent\@here\n"; +} + +sub IdentifyLocalSecret ($) { + my ($identifier) = @_; + my $secret; + + my $whoami = `/usr/bin/whoami` ; chomp $whoami; + if (open SECRETS, "< " .(getpwuid($<))[7]. "/.secret\@here") { + my $line; + while (defined ($line = <SECRETS>)) { + my ($id, $sec) = split /[\s]/, $line; + if ((defined $id) && ($id eq $identifier)) { + $secret = $sec; + last; + } + } + close SECRETS; + } + + return $secret; +} + diff --git a/Linux-PAM/modules/Makefile b/Linux-PAM/modules/Makefile new file mode 100644 index 00000000..96b3a636 --- /dev/null +++ b/Linux-PAM/modules/Makefile @@ -0,0 +1,58 @@ +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:43 hartmans Exp $ +# +# Makefile +# +# This makefile controls the build process of shared and static PAM modules. +# +# + +include ../Make.Rules + +MODDIRS=$(shell /bin/ls -d pam_*) + +all: + @echo building the static modutil library + make -C pammodutil all + @echo modules sources available are: + @ls -d $(MODDIRS) 2>/dev/null ; echo :-------- + @echo +ifdef STATIC + rm -f ./_static_module_* +endif + @for i in $(MODDIRS) ; do \ + if [ -d $$i ]; then { \ + $(MAKE) -C $$i all ; \ + if [ $$? -ne 0 ]; then exit 1 ; fi ; \ + } elif [ -f ./.$$i ]; then { \ + cat ./.$$i ; \ + } fi ; \ + done + +download: + @./download-all + +install: + for i in $(MODDIRS) ; do \ + if [ -d $$i ]; then { \ + $(MAKE) -C $$i install ; \ + if [ $$? -ne 0 ]; then exit 1 ; fi ; \ + } fi ; \ + done + +remove: + for i in $(MODDIRS) ; do \ + if [ -d $$i ]; then { \ + $(MAKE) -C $$i remove ; \ + } fi ; \ + done + +lclean: + rm -f _static_module_* + +clean: lclean + for i in $(MODDIRS) ; do \ + if [ -d $$i ]; then { \ + $(MAKE) -C $$i clean ; \ + } fi ; \ + done + make -C pammodutil clean diff --git a/Linux-PAM/modules/README b/Linux-PAM/modules/README new file mode 100644 index 00000000..73d3cf0c --- /dev/null +++ b/Linux-PAM/modules/README @@ -0,0 +1,55 @@ +This directory contains the modules. + +If you want to reserve a module name please email <pam-list@redhat.com> +and announce its name. Andrew Morgan, <morgan@linux.kernel.org>, will +add it to the Makefile in the next release of Linux-PAM. + +As of Linux-PAM-0.40 modules can optionally conform to the static +modules conventions. + +This file was updated for Linux-PAM-0.53. + +The conventions are as follows: + +There are only 6 functions that a module may declare as "public" they +fall into 4 managment groups as follows: + + functions Management group + ------------------------------------------ ---------------- + pam_sm_authenticate, pam_sm_setcred, PAM_SM_AUTH + pam_sm_acct_mgmt, PAM_SM_ACCOUNT + pam_sm_open_session, pam_sm_close_session, PAM_SM_SESSION + pam_sm_chauthtok PAM_SM_PASSWORD + +If a module contains definitions for any of the above functions, it +must supply definitions for all of the functions in the corresponding +management group. + +The header file that defines the ANSI prototypes for these functions +is <security/pam_modules.h> . In the case that the module wishes to +offer the functions of a given managment group, it must #define +PAM_SM_XXX, where XXX is one of the above four tokens. These +definitions must occur *prior* to the +#include <security/pam_modules.h> line. + +The pam_sm_... functions should be defined to be of type 'PAM_EXTERN int'. + +In the case that a module is being compiled with PAM_STATIC #define'd +it should also define a globally accessible structure +_"NAME"_modstruct containing references to each of the functions +defined by the module. (this structure is defined in +<security/pam_modules.h>. "NAME" is the title of the module +(eg. "pam_deny") + +If a module wants to be included in the static libpam.a its Makefile +should execute "register_static" with appropriate arguments (in this +directory). + +[ +For SIMPLE working examples, see + + ./modules/pam_deny/* and ./modules/pam_rootok/* +.] + +Andrew Morgan +96/11/10 diff --git a/Linux-PAM/modules/Simple.Rules b/Linux-PAM/modules/Simple.Rules new file mode 100644 index 00000000..bbbf3e50 --- /dev/null +++ b/Linux-PAM/modules/Simple.Rules @@ -0,0 +1,95 @@ +# $Id: Simple.Rules,v 1.1.1.2 2002/09/15 20:08:43 hartmans Exp $ +# +# For simple modules with no significant dependencies, set $(TITLE) +# and include this file. +# +# There are a few ways to customize this set of rules. Namely, define +# +# $(MODULE_SIMPLE_EXTRACLEAN) +# $(MODULE_SIMPLE_CLEAN) +# $(MODULE_SIMPLE_REMOVE) +# $(MODULE_SIMPLE_INSTALL) +# $(MODULE_SIMPLE_EXTRALIBS) - other things to link with the module +# $(MODULE_SIMPLE_EXTRAFILES) - other files to build (no .c suffix) +# + +LIBFILES = $(TITLE) $(MODULE_SIMPLE_EXTRAFILES) +LIBSRC = $(addsuffix .c,$(LIBFILES)) +LIBOBJ = $(addsuffix .o,$(LIBFILES)) +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +LINK_PAMMODUTILS = -L../pammodutil -lpammodutil +INCLUDE_PAMMODUTILS = -I../pammodutil/include + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif + +ifdef STATIC +LIBSTATIC = lib$(TITLE).o +endif + +####################### don't edit below ####################### + +all: dirs $(LIBSHARED) $(LIBSTATIC) register + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(INCLUDE_PAMMODUTILS) $(DYNAMIC) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(INCLUDE_PAMMODUTILS) $(STATIC) $(TARGET_ARCH) -c $< -o $@ + +dirs: +ifdef DYNAMIC + $(MKDIR) ./dynamic +endif +ifdef STATIC + $(MKDIR) ./static +endif + +register: +ifdef STATIC + ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) +endif + +ifdef DYNAMIC +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(MODULE_SIMPLE_EXTRALIBS) $(NEED_LINK_LIB_C) $(LINK_PAMMODUTILS) + +endif + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) +endif + +ifdef STATIC +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) $(MODULE_SIMPLE_EXTRALIBS) $(LINK_PAMMODUTILS) +endif + +install: all + $(MKDIR) $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + $(MODULE_SIMPLE_INSTALL) + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + $(MODULE_SIMPLE_REMOVE) + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) core *~ + $(MODULE_SIMPLE_CLEAN) + rm -f *.a *.o *.so *.bak + rm -rf dynamic static + $(MODULE_SIMPLE_EXTRACLEAN) + +.c.o: + $(CC) $(CFLAGS) -c $< + diff --git a/Linux-PAM/modules/dont_makefile b/Linux-PAM/modules/dont_makefile new file mode 100644 index 00000000..b49e9e7a --- /dev/null +++ b/Linux-PAM/modules/dont_makefile @@ -0,0 +1,21 @@ +######################################################################### +# $Id: dont_makefile,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +######################################################################### +# This is a makefile that does nothing. It is designed to be included +# by module Makefile-s when they are not compatable with the local +# system +######################################################################### + +all: + @echo "This module will not be compiled on this system" + +remove: clean + +install: clean + +clean: + @echo "Nothing to do" + +######################################################################### +# all over.. +######################################################################### diff --git a/Linux-PAM/modules/download-all b/Linux-PAM/modules/download-all new file mode 100755 index 00000000..451b3c51 --- /dev/null +++ b/Linux-PAM/modules/download-all @@ -0,0 +1,30 @@ +#!/bin/sh +# +# $Id: download-all,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +# +cat <<EOT +For a number of reasons it is not practical for Linux-PAM to be +distributed with every module out there. However, this shell script +is intended as a convenient way for users to download modules from the +'net in some semiautomated fashion. + +Please feel free to send (pam-list@redhat.com) snippets of code that +will help others to download and unpack your favorite module into the +Linux-PAM source tree. Especially welcome are snippets of the +following form: + +ncftp ftp://my.ftpsite.org/pub/fluff/pam_fluff.tar.gz +rm -fr pam_fluff +tar zvfx pam_fluff.tar.gz + +Cheers + +Andrew +morgan@linux.kernel.org +EOT + +# --- insert your snippets below --- + +# --- insert your snippets above --- + +exit 0 diff --git a/Linux-PAM/modules/install_conf b/Linux-PAM/modules/install_conf new file mode 100755 index 00000000..80f6be29 --- /dev/null +++ b/Linux-PAM/modules/install_conf @@ -0,0 +1,49 @@ +#!/bin/bash + +FAKEROOT=$1 +CONFD=$1$2 +CONFILE=$1$3 +MODULE=$4 +CONF=$5 + +IGNORE_AGE=./.ignore_age +QUIET_INSTALL=../../.quiet_install + +echo + +if [ -f "$QUIET_INSTALL" ]; then + if [ ! -f "$CONFILE" ]; then + yes="y" + else + yes="skip" + fi +elif [ -f "$IGNORE_AGE" ]; then + echo "you don't want to be bothered with the age of your $CONFILE file" + yes="n" +elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then + if [ -f "$CONFILE" ]; then + echo "An older $MODULE configuration file already exists ($CONFILE)" + echo "Do you wish to copy the $CONF file in this distribution" + echo "to $CONFILE ? (y/n) [skip] " + read yes + else + yes="y" + fi +else + yes="skip" +fi + +if [ "$yes" = "y" ]; then + mkdir -p $CONFD + echo " copying $CONF to $CONFILE" + cp $CONF $CONFILE +else + echo " Skipping $CONF installation" + if [ "$yes" = "n" ]; then + touch "$IGNORE_AGE" + fi +fi + +echo + +exit 0 diff --git a/Linux-PAM/modules/pam_access/Makefile b/Linux-PAM/modules/pam_access/Makefile new file mode 100644 index 00000000..5f8574ab --- /dev/null +++ b/Linux-PAM/modules/pam_access/Makefile @@ -0,0 +1,21 @@ +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_access +LOCAL_CONFILE=./access.conf +INSTALLED_CONFILE=$(SCONFIGD)/access.conf + +DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" +CFLAGS += $(DEFS) + +MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" +MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) +MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_access/README b/Linux-PAM/modules/pam_access/README new file mode 100644 index 00000000..ddd4725f --- /dev/null +++ b/Linux-PAM/modules/pam_access/README @@ -0,0 +1,44 @@ +# Description of its configuration file +# +# (The default config file is "/etc/security/access.conf". This +# default can be overridden with a module config argument +# 'accessfile=<full-path>'): +# +# Login access control table. +# +# When someone logs in, the table is scanned for the first entry that +# matches the (user, host) combination, or, in case of non-networked +# logins, the first entry that matches the (user, tty) combination. The +# permissions field of that table entry determines whether the login will +# be accepted or refused. +# +# Format of the login access control table is three fields separated by a +# ":" character: +# +# permission : users : origins +# +# The first field should be a "+" (access granted) or "-" (access denied) +# character. +# +# The second field should be a list of one or more login names, group +# names, or ALL (always matches). A pattern of the form user@host is +# matched when the login name matches the "user" part, and when the +# "host" part matches the local machine name. +# +# The third field should be a list of one or more tty names (for +# non-networked logins), host names, domain names (begin with "."), host +# addresses, internet network numbers (end with "."), ALL (always +# matches) or LOCAL (matches any string that does not contain a "." +# character). +# +# If you run NIS you can use @netgroupname in host or user patterns; this +# even works for @usergroup@@hostgroup patterns. Weird. +# +# The EXCEPT operator makes it possible to write very compact rules. +# +# The group file is searched only when a name does not match that of the +# logged-in user. Both the user's primary group is matched, as well as +# groups in which users are explicitly listed. +# +# Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15 +############################################################################ diff --git a/Linux-PAM/modules/pam_access/access.conf b/Linux-PAM/modules/pam_access/access.conf new file mode 100644 index 00000000..dbaadf67 --- /dev/null +++ b/Linux-PAM/modules/pam_access/access.conf @@ -0,0 +1,58 @@ +# Login access control table. +# +# When someone logs in, the table is scanned for the first entry that +# matches the (user, host) combination, or, in case of non-networked +# logins, the first entry that matches the (user, tty) combination. The +# permissions field of that table entry determines whether the login will +# be accepted or refused. +# +# Format of the login access control table is three fields separated by a +# ":" character: +# +# [Note, if you supply a 'fieldsep=|' argument to the pam_access.so +# module, you can change the field separation character to be +# '|'. This is useful for configurations where you are trying to use +# pam_access with X applications that provide PAM_TTY values that are +# the display variable like "host:0".] +# +# permission : users : origins +# +# The first field should be a "+" (access granted) or "-" (access denied) +# character. +# +# The second field should be a list of one or more login names, group +# names, or ALL (always matches). A pattern of the form user@host is +# matched when the login name matches the "user" part, and when the +# "host" part matches the local machine name. +# +# The third field should be a list of one or more tty names (for +# non-networked logins), host names, domain names (begin with "."), host +# addresses, internet network numbers (end with "."), ALL (always +# matches) or LOCAL (matches any string that does not contain a "." +# character). +# +# If you run NIS you can use @netgroupname in host or user patterns; this +# even works for @usergroup@@hostgroup patterns. Weird. +# +# The EXCEPT operator makes it possible to write very compact rules. +# +# The group file is searched only when a name does not match that of the +# logged-in user. Both the user's primary group is matched, as well as +# groups in which users are explicitly listed. +# +############################################################################## +# +# Disallow console logins to all but a few accounts. +# +#-:ALL EXCEPT wheel shutdown sync:LOCAL +# +# Disallow non-local logins to privileged accounts (group wheel). +# +#-:wheel:ALL EXCEPT LOCAL .win.tue.nl +# +# Some accounts are not allowed to login from anywhere: +# +#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL +# +# All other accounts are allowed to login from anywhere. +# diff --git a/Linux-PAM/modules/pam_access/pam_access.c b/Linux-PAM/modules/pam_access/pam_access.c new file mode 100644 index 00000000..4005c93b --- /dev/null +++ b/Linux-PAM/modules/pam_access/pam_access.c @@ -0,0 +1,497 @@ +/* pam_access module */ + +/* + * Written by Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15 + * (I took login_access from logdaemon-5.6 and converted it to PAM + * using parts of pam_time code.) + * + ************************************************************************ + * Copyright message from logdaemon-5.6 (original file name DISCLAIMER) + ************************************************************************ + * Copyright 1995 by Wietse Venema. All rights reserved. Individual files + * may be covered by other copyrights (as noted in the file itself.) + * + * This material was originally written and compiled by Wietse Venema at + * Eindhoven University of Technology, The Netherlands, in 1990, 1991, + * 1992, 1993, 1994 and 1995. + * + * Redistribution and use in source and binary forms are permitted + * provided that this entire copyright notice is duplicated in all such + * copies. + * + * This software is provided "as is" and without any expressed or implied + * warranties, including, without limitation, the implied warranties of + * merchantibility and fitness for any particular purpose. + ************************************************************************* + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <stdarg.h> +#include <syslog.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <ctype.h> +#include <sys/utsname.h> + +#ifndef BROKEN_NETWORK_MATCH +# include <netdb.h> +# include <sys/socket.h> +#endif + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_ACCOUNT + +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +int strcasecmp(const char *s1, const char *s2); + +/* login_access.c from logdaemon-5.6 with several changes by A.Nogin: */ + + /* + * This module implements a simple but effective form of login access + * control based on login names and on host (or domain) names, internet + * addresses (or network numbers), or on terminal line names in case of + * non-networked logins. Diagnostics are reported through syslog(3). + * + * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. + */ + +#if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 64) +#undef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#ifdef DEFAULT_CONF_FILE +# define PAM_ACCESS_CONFIG DEFAULT_CONF_FILE +#else +# define PAM_ACCESS_CONFIG "/etc/security/access.conf" +#endif + + /* Delimiters for fields and for lists of users, ttys or hosts. */ + +static const char *fs = ":"; /* field separator */ +static const char sep[] = ", \t"; /* list-element separator */ + + /* Constants to be used in assignments only, not in comparisons... */ + +#define YES 1 +#define NO 0 + + /* + * A structure to bundle up all login-related information to keep the + * functional interfaces as generic as possible. + */ +struct login_info { + struct passwd *user; + char *from; + const char *config_file; + const char *service; +}; + +/* --- static functions for checking whether the user should be let in --- */ + +static void _log_err(const char *format, ... ) +{ + va_list args; + + va_start(args, format); + openlog("pam_access", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(LOG_ERR, format, args); + va_end(args); + closelog(); +} + +/* Parse module config arguments */ + +static int parse_args(struct login_info *loginfo, int argc, const char **argv) +{ + int i; + + for (i=0; i<argc; ++i) { + if (!strncmp("fieldsep=", argv[i], 9)) { + + /* the admin wants to override the default field separators */ + fs = argv[i]+9; + + } else if (!strncmp("accessfile=", argv[i], 11)) { + FILE *fp = fopen(11 + argv[i], "r"); + + if (fp) { + loginfo->config_file = 11 + argv[i]; + fclose(fp); + } else { + _log_err("for service [%s] failed to open accessfile=[%s]" + , loginfo->service, 11 + argv[i]); + return 0; + } + + } else { + _log_err("unrecognized option [%s]", argv[i]); + } + } + + return 1; /* OK */ +} + +typedef int match_func (char *, struct login_info *); + +static int list_match (char *, struct login_info *, + match_func *); +static int user_match (char *, struct login_info *); +static int from_match (char *, struct login_info *); +static int string_match (char *, char *); + +/* login_access - match username/group and host/tty with access control file */ + +static int login_access(struct login_info *item) +{ + FILE *fp; + char line[BUFSIZ]; + char *perm; /* becomes permission field */ + char *users; /* becomes list of login names */ + char *froms; /* becomes list of terminals or hosts */ + int match = NO; + int end; + int lineno = 0; /* for diagnostics */ + + /* + * Process the table one line at a time and stop at the first match. + * Blank lines and lines that begin with a '#' character are ignored. + * Non-comment lines are broken at the ':' character. All fields are + * mandatory. The first field should be a "+" or "-" character. A + * non-existing table means no access control. + */ + + if ((fp = fopen(item->config_file, "r"))!=NULL) { + while (!match && fgets(line, sizeof(line), fp)) { + lineno++; + if (line[end = strlen(line) - 1] != '\n') { + _log_err("%s: line %d: missing newline or line too long", + item->config_file, lineno); + continue; + } + if (line[0] == '#') + continue; /* comment line */ + while (end > 0 && isspace(line[end - 1])) + end--; + line[end] = 0; /* strip trailing whitespace */ + if (line[0] == 0) /* skip blank lines */ + continue; + if (!(perm = strtok(line, fs)) + || !(users = strtok((char *) 0, fs)) + || !(froms = strtok((char *) 0, fs)) + || strtok((char *) 0, fs)) { + _log_err("%s: line %d: bad field count", + item->config_file, lineno); + continue; + } + if (perm[0] != '+' && perm[0] != '-') { + _log_err("%s: line %d: bad first field", + item->config_file, lineno); + continue; + } + match = (list_match(froms, item, from_match) + && list_match(users, item, user_match)); + } + (void) fclose(fp); + } else if (errno != ENOENT) { + _log_err("cannot open %s: %m", item->config_file); + } + return (match == 0 || (line[0] == '+')); +} + +/* list_match - match an item against a list of tokens with exceptions */ + +static int list_match(char *list, struct login_info *item, match_func *match_fn) +{ + char *tok; + int match = NO; + + /* + * Process tokens one at a time. We have exhausted all possible matches + * when we reach an "EXCEPT" token or the end of the list. If we do find + * a match, look for an "EXCEPT" list and recurse to determine whether + * the match is affected by any exceptions. + */ + + for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { + if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ + break; + if ((match = (*match_fn) (tok, item))) /* YES */ + break; + } + /* Process exceptions to matches. */ + + if (match != NO) { + while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) + /* VOID */ ; + if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) + return (match); + } + return (NO); +} + +/* myhostname - figure out local machine name */ + +static char * myhostname(void) +{ + static char name[MAXHOSTNAMELEN + 1]; + + gethostname(name, MAXHOSTNAMELEN); + name[MAXHOSTNAMELEN] = 0; + return (name); +} + +/* netgroup_match - match group against machine or user */ + +static int netgroup_match(char *group, char *machine, char *user) +{ +#ifdef NIS + static char *mydomain = 0; + + if (mydomain == 0) + yp_get_default_domain(&mydomain); + return (innetgr(group, machine, user, mydomain)); +#else + _log_err("NIS netgroup support not configured"); + return (NO); +#endif +} + +/* user_match - match a username against one token */ + +static int user_match(char *tok, struct login_info *item) +{ + char *string = item->user->pw_name; + struct login_info fake_item; + struct group *group; + int i; + char *at; + + /* + * If a token has the magic value "ALL" the match always succeeds. + * Otherwise, return YES if the token fully matches the username, if the + * token is a group that contains the username, or if the token is the + * name of the user's primary group. + */ + + if ((at = strchr(tok + 1, '@')) != 0) { /* split user@host pattern */ + *at = 0; + fake_item.from = myhostname(); + return (user_match(tok, item) && from_match(at + 1, &fake_item)); + } else if (tok[0] == '@') { /* netgroup */ + return (netgroup_match(tok + 1, (char *) 0, string)); + } else if (string_match(tok, string)) { /* ALL or exact match */ + return (YES); + } else if ((group = getgrnam(tok))) { /* try group membership */ + if (item->user->pw_gid == group->gr_gid) + return (YES); + for (i = 0; group->gr_mem[i]; i++) + if (strcasecmp(string, group->gr_mem[i]) == 0) + return (YES); + } + return (NO); +} + +/* from_match - match a host or tty against a list of tokens */ + +static int from_match(char *tok, struct login_info *item) +{ + char *string = item->from; + int tok_len; + int str_len; + + /* + * If a token has the magic value "ALL" the match always succeeds. Return + * YES if the token fully matches the string. If the token is a domain + * name, return YES if it matches the last fields of the string. If the + * token has the magic value "LOCAL", return YES if the string does not + * contain a "." character. If the token is a network number, return YES + * if it matches the head of the string. + */ + + if (tok[0] == '@') { /* netgroup */ + return (netgroup_match(tok + 1, string, (char *) 0)); + } else if (string_match(tok, string)) { /* ALL or exact match */ + return (YES); + } else if (tok[0] == '.') { /* domain: match last fields */ + if ((str_len = strlen(string)) > (tok_len = strlen(tok)) + && strcasecmp(tok, string + str_len - tok_len) == 0) + return (YES); + } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ + if (strchr(string, '.') == 0) + return (YES); +#ifdef BROKEN_NETWORK_MATCH + } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ + && strncmp(tok, string, tok_len) == 0) { + return (YES); +#else /* BROKEN_NETWORK_MATCH */ + } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { + /* + The code below does a more correct check if the address specified + by "string" starts from "tok". + 1998/01/27 Andrey V. Savochkin <saw@msu.ru> + */ + + struct hostent *h; + char hn[3+1+3+1+3+1+3+1+1]; + int r; + + h = gethostbyname(string); + if (h == NULL) + return (NO); + if (h->h_addrtype != AF_INET) + return (NO); + if (h->h_length != 4) + return (NO); /* only IPv4 addresses (SAW) */ + r = snprintf(hn, sizeof(hn), "%u.%u.%u.%u.", + (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], + (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]); + if (r < 0 || r >= sizeof(hn)) + return (NO); + if (!strncmp(tok, hn, tok_len)) + return (YES); +#endif /* BROKEN_NETWORK_MATCH */ + } + return (NO); +} + +/* string_match - match a string against one token */ + +static int string_match(char *tok, char *string) +{ + + /* + * If the token has the magic value "ALL" the match always succeeds. + * Otherwise, return YES if the token fully matches the string. + */ + + if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ + return (YES); + } else if (strcasecmp(tok, string) == 0) { /* try exact match */ + return (YES); + } + return (NO); +} + +/* end of login_access.c */ + +int strcasecmp(const char *s1, const char *s2) +{ + while ((toupper(*s1)==toupper(*s2)) && (*s1) && (*s2)) {s1++; s2++;} + return(toupper(*s1)-toupper(*s2)); +} + +/* --- public account management functions --- */ + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + struct login_info loginfo; + const char *user=NULL, *service=NULL; + char *from=NULL; + struct passwd *user_pw; + + if ((pam_get_item(pamh, PAM_SERVICE, (const void **)&service) + != PAM_SUCCESS) || (service == NULL) || (*service == ' ')) { + _log_err("cannot find the service name"); + return PAM_ABORT; + } + + /* set username */ + + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL + || *user == '\0') { + _log_err("cannot determine the user's name"); + return PAM_USER_UNKNOWN; + } + + /* remote host name */ + + if (pam_get_item(pamh, PAM_RHOST, (const void **)&from) + != PAM_SUCCESS) { + _log_err("cannot find the remote host name"); + return PAM_ABORT; + } + + if ((from==NULL) || (*from=='\0')) { + + /* local login, set tty name */ + + if (pam_get_item(pamh, PAM_TTY, (const void **)&from) != PAM_SUCCESS + || from == NULL) { + D(("PAM_TTY not set, probing stdin")); + from = ttyname(STDIN_FILENO); + if (from == NULL) { + _log_err("couldn't get the tty name"); + return PAM_ABORT; + } + if (pam_set_item(pamh, PAM_TTY, from) != PAM_SUCCESS) { + _log_err("couldn't set tty name"); + return PAM_ABORT; + } + } + if (strncmp("/dev/",from,5) == 0) { /* strip leading /dev/ */ + from += 5; + } + + } + + if ((user_pw=getpwnam(user))==NULL) return (PAM_USER_UNKNOWN); + + /* + * Bundle up the arguments to avoid unnecessary clumsiness later on. + */ + loginfo.user = user_pw; + loginfo.from = from; + loginfo.service = service; + loginfo.config_file = PAM_ACCESS_CONFIG; + + /* parse the argument list */ + + if (!parse_args(&loginfo, argc, argv)) { + _log_err("failed to parse the module arguments"); + return PAM_ABORT; + } + + if (login_access(&loginfo)) { + return (PAM_SUCCESS); + } else { + _log_err("access denied for user `%s' from `%s'",user,from); + return (PAM_PERM_DENIED); + } +} + +/* end of module definition */ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_access_modstruct = { + "pam_access", + NULL, + NULL, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL +}; +#endif + diff --git a/Linux-PAM/modules/pam_cracklib/Makefile b/Linux-PAM/modules/pam_cracklib/Makefile new file mode 100644 index 00000000..9e8f69aa --- /dev/null +++ b/Linux-PAM/modules/pam_cracklib/Makefile @@ -0,0 +1,32 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:17 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@kernel.org> 2000/10/08 +# + +include ../../Make.Rules + +TITLE=pam_cracklib + +ifeq ($(HAVE_LIBCRACK),yes) +BUILD_THIS_MODULE=yes +MODULE_SIMPLE_EXTRALIBS=-lcrack + +# These two should really be provided by ../../pam_aconf.h +CFLAGS+=-DCRACKLIB_DICTPATH=\"$(CRACKLIB_DICTPATH)\" + +ifeq ($(HAVE_LIBCRYPT),yes) + MODULE_SIMPLE_EXTRALIBS += -lcrypt +endif + +endif + +ifeq ($(BUILD_THIS_MODULE),yes) + include ../Simple.Rules +else + include ../dont_makefile +endif diff --git a/Linux-PAM/modules/pam_cracklib/README b/Linux-PAM/modules/pam_cracklib/README new file mode 100644 index 00000000..69662f73 --- /dev/null +++ b/Linux-PAM/modules/pam_cracklib/README @@ -0,0 +1,37 @@ + +pam_cracklib: + check the passwd against dictionary words. + +RECOGNIZED ARGUMENTS: + debug verbose log + + type=XXX alter the message printed as a prompt to the user. + the message printed is in the form + "New XXX password: ". + Default XXX=UNIX + + retry=N Prompt user at most N times before returning with + error. Default N=1. + + difok=N How many characters can be the same in the new + password relative to the old + difignore=N How many characters long should the password be + before we ignore difok. + + minlen=N The minimum simplicity count for a good password. + + dcredit=N + ucredit=N + lcredit=N + ocredit=N Weight, digits, upper, lower, other characters with + count N. Use these values to compute the + 'unsimplicity' of the password. + + use_authtok Get the proposed password from PAM_AUTHTOK + +MODULE SERVICES PROVIDED: + passwd chauthtok + +AUTHOR: + Cristian Gafton <gafton@redhat.com> + diff --git a/Linux-PAM/modules/pam_cracklib/pam_cracklib.c b/Linux-PAM/modules/pam_cracklib/pam_cracklib.c new file mode 100644 index 00000000..fa415e32 --- /dev/null +++ b/Linux-PAM/modules/pam_cracklib/pam_cracklib.c @@ -0,0 +1,888 @@ +/* + * pam_cracklib module + * $Id: pam_cracklib.c,v 1.1.1.2 2002/09/15 20:08:45 hartmans Exp $ + */ + +/* + * 0.9. switch to using a distance algorithm in similar() + * 0.86. added support for setting minimum numbers of digits, uppers, + * lowers, and others + * 0.85. added six new options to use this with long passwords. + * 0.8. tidied output and improved D(()) usage for debugging. + * 0.7. added support for more obscure checks for new passwd. + * 0.6. root can reset user passwd to any values (it's only warned) + * 0.5. supports retries - 'retry=N' argument + * 0.4. added argument 'type=XXX' for 'New XXX password' prompt + * 0.3. Added argument 'debug' + * 0.2. new password is feeded to cracklib for verify after typed once + * 0.1. First release + */ + +/* + * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 + * Long password support by Philip W. Dalrymple <pwd@mdtsoft.com> 1997/07/18 + * See the end of the file for Copyright Information + * + * Modification for long password systems (>8 chars). The original + * module had problems when used in a md5 password system in that it + * allowed too short passwords but required that at least half of the + * bytes in the new password did not appear in the old one. this + * action is still the default and the changes should not break any + * current user. This modification adds 6 new options, one to set the + * number of bytes in the new password that are not in the old one, + * the other five to control the length checking, these are all + * documented (or will be before anyone else sees this code) in the PAM + * S.A.G. in the section on the cracklib module. + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#ifdef HAVE_CRYPT_H +# include <crypt.h> +#endif +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> + +extern char *FascistCheck(char *pw, const char *dictpath); + +#ifndef CRACKLIB_DICTPATH +#define CRACKLIB_DICTPATH "/usr/share/dict/cracklib_dict" +#endif + +#define PROMPT1 "New %s%spassword: " +#define PROMPT2 "Retype new %s%spassword: " +#define MISTYPED_PASS "Sorry, passwords do not match" + +#ifdef MIN +#undef MIN +#endif +#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-Cracklib", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ +#define PAM_DEBUG_ARG 0x0001 + +struct cracklib_options { + int retry_times; + int diff_ok; + int diff_ignore; + int min_length; + int dig_credit; + int up_credit; + int low_credit; + int oth_credit; + int use_authtok; + char prompt_type[BUFSIZ]; +}; + +#define CO_RETRY_TIMES 1 +#define CO_DIFF_OK 5 +#define CO_DIFF_IGNORE 23 +#define CO_MIN_LENGTH 9 +# define CO_MIN_LENGTH_BASE 5 +#define CO_DIG_CREDIT 1 +#define CO_UP_CREDIT 1 +#define CO_LOW_CREDIT 1 +#define CO_OTH_CREDIT 1 +#define CO_USE_AUTHTOK 0 + +static int _pam_parse(struct cracklib_options *opt, int argc, const char **argv) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + char *ep = NULL; + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strncmp(*argv,"type=",5)) + strncpy(opt->prompt_type, *argv+5, sizeof(opt->prompt_type) - 1); + else if (!strncmp(*argv,"retry=",6)) { + opt->retry_times = strtol(*argv+6,&ep,10); + if (!ep || (opt->retry_times < 1)) + opt->retry_times = CO_RETRY_TIMES; + } else if (!strncmp(*argv,"difok=",6)) { + opt->diff_ok = strtol(*argv+6,&ep,10); + if (!ep || (opt->diff_ok < 0)) + opt->diff_ok = CO_DIFF_OK; + } else if (!strncmp(*argv,"difignore=",10)) { + opt->diff_ignore = strtol(*argv+10,&ep,10); + if (!ep || (opt->diff_ignore < 0)) + opt->diff_ignore = CO_DIFF_IGNORE; + } else if (!strncmp(*argv,"minlen=",7)) { + opt->min_length = strtol(*argv+7,&ep,10); + if (!ep || (opt->min_length < CO_MIN_LENGTH_BASE)) + opt->min_length = CO_MIN_LENGTH_BASE; + } else if (!strncmp(*argv,"dcredit=",8)) { + opt->dig_credit = strtol(*argv+8,&ep,10); + if (!ep) + opt->dig_credit = 0; + } else if (!strncmp(*argv,"ucredit=",8)) { + opt->up_credit = strtol(*argv+8,&ep,10); + if (!ep) + opt->up_credit = 0; + } else if (!strncmp(*argv,"lcredit=",8)) { + opt->low_credit = strtol(*argv+8,&ep,10); + if (!ep) + opt->low_credit = 0; + } else if (!strncmp(*argv,"ocredit=",8)) { + opt->oth_credit = strtol(*argv+8,&ep,10); + if (!ep) + opt->oth_credit = 0; + } else if (!strncmp(*argv,"use_authtok",11)) { + opt->use_authtok = 1; + } else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + opt->prompt_type[sizeof(opt->prompt_type) - 1] = '\0'; + + return ctrl; +} + +/* Helper functions */ + +/* this is a front-end for module-application conversations */ +static int converse(pam_handle_t *pamh, int ctrl, int nargs, + struct pam_message **message, + struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + + if ( retval == PAM_SUCCESS ) { + retval = conv->conv(nargs, (const struct pam_message **)message, + response, conv->appdata_ptr); + if (retval != PAM_SUCCESS && (ctrl && PAM_DEBUG_ARG)) { + _pam_log(LOG_DEBUG, "conversation failure [%s]", + pam_strerror(pamh, retval)); + } + } else { + _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]", + pam_strerror(pamh, retval)); + } + + return retval; /* propagate error status */ +} + +static int make_remark(pam_handle_t *pamh, unsigned int ctrl, + int type, const char *text) +{ + struct pam_message *pmsg[1], msg[1]; + struct pam_response *resp; + int retval; + + pmsg[0] = &msg[0]; + msg[0].msg = text; + msg[0].msg_style = type; + resp = NULL; + + retval = converse(pamh, ctrl, 1, pmsg, &resp); + if (retval == PAM_SUCCESS) + _pam_drop_reply(resp, 1); + + return retval; +} + +/* use this to free strings. ESPECIALLY password strings */ +static char *_pam_delete(register char *xx) +{ + _pam_overwrite(xx); + free(xx); + return NULL; +} + +/* + * can't be a palindrome - like `R A D A R' or `M A D A M' + */ +static int palindrome(const char *old, const char *new) +{ + int i, j; + + i = strlen (new); + + for (j = 0;j < i;j++) + if (new[i - j - 1] != new[j]) + return 0; + + return 1; +} + +/* + * Calculate how different two strings are in terms of the number of + * character removals, additions, and changes needed to go from one to + * the other + */ + +static int distdifferent(const char *old, const char *new, int i, int j) +{ + char c, d; + + if ((i == 0) || (strlen(old) <= i)) { + c = 0; + } else { + c = old[i - 1]; + } + if ((j == 0) || (strlen(new) <= i)) { + d = 0; + } else { + d = new[j - 1]; + } + return (c != d); +} + +static int distcalculate(int **distances, const char *old, const char *new, + int i, int j) +{ + int tmp = 0; + + if (distances[i][j] != -1) { + return distances[i][j]; + } + + tmp = distcalculate(distances, old, new, i - 1, j - 1); + tmp = MIN(tmp, distcalculate(distances, old, new, i, j - 1)); + tmp = MIN(tmp, distcalculate(distances, old, new, i - 1, j)); + tmp += distdifferent(old, new, i, j); + + distances[i][j] = tmp; + + return tmp; +} + +static int distance(const char *old, const char *new) +{ + int **distances = NULL; + int m, n, i, j, r; + + m = strlen(old); + n = strlen(new); + distances = malloc(sizeof(int*) * (m + 1)); + + for (i = 0; i <= m; i++) { + distances[i] = malloc(sizeof(int) * (n + 1)); + for(j = 0; j <= n; j++) { + distances[i][j] = -1; + } + } + for (i = 0; i <= m; i++) { + distances[i][0] = i; + } + for (j = 0; j <= n; j++) { + distances[0][j] = j; + } + distances[0][0] = 0; + + r = distcalculate(distances, old, new, m, n); + + for (i = 0; i <= m; i++) { + memset(distances[i], 0, sizeof(int) * (n + 1)); + free(distances[i]); + } + free(distances); + + return r; +} + +static int similar(struct cracklib_options *opt, + const char *old, const char *new) +{ + if (distance(old, new) >= opt->diff_ok) { + return 0; + } + + if (strlen(new) >= (strlen(old) * 2)) { + return 0; + } + + /* passwords are too similar */ + return 1; +} + +/* + * a nice mix of characters. + */ +static int simple(struct cracklib_options *opt, + const char *old, const char *new) +{ + int digits = 0; + int uppers = 0; + int lowers = 0; + int others = 0; + int size; + int i; + + for (i = 0;new[i];i++) { + if (isdigit (new[i])) + digits++; + else if (isupper (new[i])) + uppers++; + else if (islower (new[i])) + lowers++; + else + others++; + } + + /* + * The scam was this - a password of only one character type + * must be 8 letters long. Two types, 7, and so on. + * This is now changed, the base size and the credits or defaults + * see the docs on the module for info on these parameters, the + * defaults cause the effect to be the same as before the change + */ + + if ((opt->dig_credit >= 0) && (digits > opt->dig_credit)) + digits = opt->dig_credit; + + if ((opt->up_credit >= 0) && (uppers > opt->up_credit)) + uppers = opt->up_credit; + + if ((opt->low_credit >= 0) && (lowers > opt->low_credit)) + lowers = opt->low_credit; + + if ((opt->oth_credit >= 0) && (others > opt->oth_credit)) + others = opt->oth_credit; + + size = opt->min_length; + + if (opt->dig_credit >= 0) + size -= digits; + else if (digits < opt->dig_credit * -1) + return 1; + + if (opt->up_credit >= 0) + size -= uppers; + else if (uppers < opt->up_credit * -1) + return 1; + + if (opt->low_credit >= 0) + size -= lowers; + else if (lowers < opt->low_credit * -1) + return 1; + + if (opt->oth_credit >= 0) + size -= others; + else if (others < opt->oth_credit * -1) + return 1; + + if (size <= i) + return 0; + + return 1; +} + +static char * str_lower(char *string) +{ + char *cp; + + for (cp = string; *cp; cp++) + *cp = tolower(*cp); + return string; +} + +static const char * password_check(struct cracklib_options *opt, const char *old, const char *new) +{ + const char *msg = NULL; + char *oldmono, *newmono, *wrapped; + + if (strcmp(new, old) == 0) { + msg = "is the same as the old one"; + return msg; + } + + newmono = str_lower(x_strdup(new)); + oldmono = str_lower(x_strdup(old)); + wrapped = malloc(strlen(oldmono) * 2 + 1); + strcpy (wrapped, oldmono); + strcat (wrapped, oldmono); + + if (palindrome(oldmono, newmono)) + msg = "is a palindrome"; + + if (!msg && strcmp(oldmono, newmono) == 0) + msg = "case changes only"; + + if (!msg && similar(opt, oldmono, newmono)) + msg = "is too similar to the old one"; + + if (!msg && simple(opt, old, new)) + msg = "is too simple"; + + if (!msg && strstr(wrapped, newmono)) + msg = "is rotated"; + + memset(newmono, 0, strlen(newmono)); + memset(oldmono, 0, strlen(oldmono)); + memset(wrapped, 0, strlen(wrapped)); + free(newmono); + free(oldmono); + free(wrapped); + + return msg; +} + + +#define OLD_PASSWORDS_FILE "/etc/security/opasswd" + +static const char * check_old_password(const char *forwho, const char *newpass) +{ + static char buf[16384]; + char *s_luser, *s_uid, *s_npas, *s_pas; + const char *msg = NULL; + FILE *opwfile; + + opwfile = fopen(OLD_PASSWORDS_FILE, "r"); + if (opwfile == NULL) + return NULL; + + while (fgets(buf, 16380, opwfile)) { + if (!strncmp(buf, forwho, strlen(forwho))) { + buf[strlen(buf)-1] = '\0'; + s_luser = strtok(buf, ":,"); + s_uid = strtok(NULL, ":,"); + s_npas = strtok(NULL, ":,"); + s_pas = strtok(NULL, ":,"); + while (s_pas != NULL) { + if (!strcmp(crypt(newpass, s_pas), s_pas)) { + msg = "has been already used"; + break; + } + s_pas = strtok(NULL, ":,"); + } + break; + } + } + fclose(opwfile); + + return msg; +} + + +static int _pam_unix_approve_pass(pam_handle_t *pamh, + unsigned int ctrl, + struct cracklib_options *opt, + const char *pass_old, + const char *pass_new) +{ + const char *msg = NULL; + const char *user; + int retval; + + if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { + if (ctrl && PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "bad authentication token"); + make_remark(pamh, ctrl, PAM_ERROR_MSG, + pass_new == NULL ? + "No password supplied":"Password unchanged" ); + return PAM_AUTHTOK_ERR; + } + + /* + * if one wanted to hardwire authentication token strength + * checking this would be the place + */ + msg = password_check(opt, pass_old,pass_new); + if (!msg) { + retval = pam_get_item(pamh, PAM_USER, (const void **)&user); + if (retval != PAM_SUCCESS) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_ERR,"Can not get username"); + return PAM_AUTHTOK_ERR; + } + } + msg = check_old_password(user, pass_new); + } + + if (msg) { + char remark[BUFSIZ]; + + memset(remark,0,sizeof(remark)); + snprintf(remark,sizeof(remark),"BAD PASSWORD: %s",msg); + if (ctrl && PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE, "new passwd fails strength check: %s", + msg); + make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); + return PAM_AUTHTOK_ERR; + }; + return PAM_SUCCESS; + +} + +/* The Main Thing (by Cristian Gafton, CEO at this module :-) + * (stolen from http://home.netscape.com) + */ +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + struct cracklib_options options; + + D(("called.")); + + options.retry_times = CO_RETRY_TIMES; + options.diff_ok = CO_DIFF_OK; + options.diff_ignore = CO_DIFF_IGNORE; + options.min_length = CO_MIN_LENGTH; + options.dig_credit = CO_DIG_CREDIT; + options.up_credit = CO_UP_CREDIT; + options.low_credit = CO_LOW_CREDIT; + options.oth_credit = CO_OTH_CREDIT; + options.use_authtok = CO_USE_AUTHTOK; + memset(options.prompt_type, 0, BUFSIZ); + strcpy(options.prompt_type,"UNIX"); + + ctrl = _pam_parse(&options, argc, argv); + + if (flags & PAM_PRELIM_CHECK) { + /* Check for passwd dictionary */ + struct stat st; + char buf[sizeof(CRACKLIB_DICTPATH)+10]; + + D(("prelim check")); + + memset(buf,0,sizeof(buf)); /* zero the buffer */ + snprintf(buf,sizeof(buf),"%s.pwd",CRACKLIB_DICTPATH); + + if (!stat(buf,&st) && st.st_size) + return PAM_SUCCESS; + else { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"dict path '%s'[.pwd] is invalid", + CRACKLIB_DICTPATH); + return PAM_ABORT; + } + + /* Not reached */ + return PAM_SERVICE_ERR; + + } else if (flags & PAM_UPDATE_AUTHTOK) { + int retval; + char *token1, *token2, *oldtoken; + struct pam_message msg[1],*pmsg[1]; + struct pam_response *resp; + const char *cracklib_dictpath = CRACKLIB_DICTPATH; + char prompt[BUFSIZ]; + + D(("do update")); + retval = pam_get_item(pamh, PAM_OLDAUTHTOK, + (const void **)&oldtoken); + if (retval != PAM_SUCCESS) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_ERR,"Can not get old passwd"); + oldtoken=NULL; + retval = PAM_SUCCESS; + } + + do { + /* + * make sure nothing inappropriate gets returned + */ + token1 = token2 = NULL; + + if (!options.retry_times) { + D(("returning %s because maxtries reached", + pam_strerror(pamh, retval))); + return retval; + } + + /* Planned modus operandi: + * Get a passwd. + * Verify it against cracklib. + * If okay get it a second time. + * Check to be the same with the first one. + * set PAM_AUTHTOK and return + */ + + if (options.use_authtok == 1) { + const char *item = NULL; + + retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item); + if (retval != PAM_SUCCESS) { + /* very strange. */ + _pam_log(LOG_ALERT + ,"pam_get_item returned error to pam_cracklib" + ); + } else if (item != NULL) { /* we have a password! */ + token1 = x_strdup(item); + item = NULL; + } else { + retval = PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ + } + + } else { + /* Prepare to ask the user for the first time */ + memset(prompt,0,sizeof(prompt)); + snprintf(prompt,sizeof(prompt),PROMPT1, + options.prompt_type, options.prompt_type[0]?" ":""); + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = prompt; + + resp = NULL; + retval = converse(pamh, ctrl, 1, pmsg, &resp); + if (resp != NULL) { + /* interpret the response */ + if (retval == PAM_SUCCESS) { /* a good conversation */ + token1 = x_strdup(resp[0].resp); + if (token1 == NULL) { + _pam_log(LOG_NOTICE, + "could not recover authentication token 1"); + retval = PAM_AUTHTOK_RECOVER_ERR; + } + } + /* + * tidy up the conversation (resp_retcode) is ignored + */ + _pam_drop_reply(resp, 1); + } else { + retval = (retval == PAM_SUCCESS) ? + PAM_AUTHTOK_RECOVER_ERR:retval ; + } + } + + if (retval != PAM_SUCCESS) { + if (ctrl && PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"unable to obtain a password"); + continue; + } + + D(("testing password, retval = %s", pam_strerror(pamh, retval))); + /* now test this passwd against cracklib */ + { + char *crack_msg; + char remark[BUFSIZ]; + + bzero(remark,sizeof(remark)); + D(("against cracklib")); + if ((crack_msg = FascistCheck(token1, cracklib_dictpath))) { + if (ctrl && PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"bad password: %s",crack_msg); + snprintf(remark,sizeof(remark),"BAD PASSWORD: %s", crack_msg); + make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); + if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) + retval = PAM_AUTHTOK_ERR; + else + retval = PAM_SUCCESS; + } else { + /* check it for strength too... */ + D(("for strength")); + if (oldtoken) { + retval = _pam_unix_approve_pass(pamh,ctrl,&options, + oldtoken,token1); + if (retval != PAM_SUCCESS) { + if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) + retval = PAM_AUTHTOK_ERR; + else + retval = PAM_SUCCESS; + } + } + } + } + + D(("after testing: retval = %s", pam_strerror(pamh, retval))); + /* if cracklib/strength check said it is a bad passwd... */ + if ((retval != PAM_SUCCESS) && (retval != PAM_IGNORE)) { + int temp_unused; + + temp_unused = pam_set_item(pamh, PAM_AUTHTOK, NULL); + token1 = _pam_delete(token1); + continue; + } + + /* Now we have a good passwd. Ask for it once again */ + + if (options.use_authtok == 0) { + bzero(prompt,sizeof(prompt)); + snprintf(prompt,sizeof(prompt),PROMPT2, + options.prompt_type, options.prompt_type[0]?" ":""); + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = prompt; + + resp = NULL; + retval = converse(pamh, ctrl, 1, pmsg, &resp); + if (resp != NULL) { + /* interpret the response */ + if (retval == PAM_SUCCESS) { /* a good conversation */ + token2 = x_strdup(resp[0].resp); + if (token2 == NULL) { + _pam_log(LOG_NOTICE, + "could not recover authentication token 2"); + retval = PAM_AUTHTOK_RECOVER_ERR; + } + } + /* + * tidy up the conversation (resp_retcode) is ignored + */ + _pam_drop_reply(resp, 1); + } else { + retval = (retval == PAM_SUCCESS) ? + PAM_AUTHTOK_RECOVER_ERR:retval ; + } + + if (retval != PAM_SUCCESS) { + if (ctrl && PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG + ,"unable to obtain the password a second time"); + continue; + } + + /* Hopefully now token1 and token2 the same password ... */ + if (strcmp(token1,token2) != 0) { + /* tell the user */ + make_remark(pamh, ctrl, PAM_ERROR_MSG, MISTYPED_PASS); + token1 = _pam_delete(token1); + token2 = _pam_delete(token2); + pam_set_item(pamh, PAM_AUTHTOK, NULL); + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"Password mistyped"); + retval = PAM_AUTHTOK_RECOVER_ERR; + continue; + } + + /* Yes, the password was typed correct twice + * we store this password as an item + */ + + { + const char *item = NULL; + + retval = pam_set_item(pamh, PAM_AUTHTOK, token1); + + /* clean up */ + token1 = _pam_delete(token1); + token2 = _pam_delete(token2); + + if ( (retval != PAM_SUCCESS) || + ((retval = pam_get_item(pamh, PAM_AUTHTOK, + (const void **)&item) + ) != PAM_SUCCESS) ) { + _pam_log(LOG_CRIT, "error manipulating password"); + continue; + } + item = NULL; /* break link to password */ + return PAM_SUCCESS; + } + } + + } while (options.retry_times--); + + } else { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE, "UNKNOWN flags setting %02X",flags); + return PAM_SERVICE_ERR; + } + + /* Not reached */ + return PAM_SERVICE_ERR; +} + + + +#ifdef PAM_STATIC +/* static module data */ +struct pam_module _pam_cracklib_modstruct = { + "pam_cracklib", + NULL, + NULL, + NULL, + NULL, + NULL, + pam_sm_chauthtok +}; +#endif + +/* + * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996. + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The following copyright was appended for the long password support + * added with the libpam 0.58 release: + * + * Modificaton Copyright (c) Philip W. Dalrymple III <pwd@mdtsoft.com> + * 1997. All rights reserved + * + * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_debug/Makefile b/Linux-PAM/modules/pam_debug/Makefile new file mode 100644 index 00000000..bb759918 --- /dev/null +++ b/Linux-PAM/modules/pam_debug/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_debug + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_debug/README b/Linux-PAM/modules/pam_debug/README new file mode 100644 index 00000000..c1dad0f8 --- /dev/null +++ b/Linux-PAM/modules/pam_debug/README @@ -0,0 +1,15 @@ +# $Id: README,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ +# + +This module returns what its module arguments tell it to return. It +can be used for debugging libpam and/or an application. + +Here are some example ways to use it: + +auth requisite pam_permit.so +auth [success=2 default=ok] pam_debug.so auth=perm_denied cred=success +auth [default=reset] pam_debug.so auth=success cred=perm_denied +auth [success=done default=die] pam_debug.so +auth optional pam_debug.so auth=perm_denied cred=perm_denied +auth sufficient pam_debug.so auth=success cred=success + diff --git a/Linux-PAM/modules/pam_debug/pam_debug.c b/Linux-PAM/modules/pam_debug/pam_debug.c new file mode 100644 index 00000000..6226c829 --- /dev/null +++ b/Linux-PAM/modules/pam_debug/pam_debug.c @@ -0,0 +1,175 @@ +/* pam_permit module */ + +/* + * $Id: pam_debug.c,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@kernel.org> 2001/02/04 + * + */ + +#define DEFAULT_USER "nobody" + +#include <stdio.h> + +/* + * This module is intended as a debugging aide for determining how + * the PAM stack is operating. + * + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +#define _PAM_ACTION_UNDEF (-10) +#include "../../libpam/pam_tokens.h" + +/* --- authentication management functions --- */ + +static int state(pam_handle_t *pamh, const char *text) +{ + int retval; + struct pam_conv *conv; + struct pam_message msg[1], *mesg[1]; + struct pam_response *response; + + retval = pam_get_item(pamh, PAM_CONV, (const void **)&conv); + if ((retval != PAM_SUCCESS) || (conv == NULL)) { + D(("failed to obtain conversation function")); + return PAM_ABORT; + } + + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = text; + mesg[0] = &msg[0]; + + retval = conv->conv(1, (const struct pam_message **) mesg, + &response, conv->appdata_ptr); + if (retval != PAM_SUCCESS) { + D(("conversation failed")); + } + + return retval; +} + +static int parse_args(int retval, const char *event, + pam_handle_t *pamh, int argc, const char **argv) +{ + int i; + + for (i=0; i<argc; ++i) { + int length = strlen(event); + if (!strncmp(event, argv[i], length) && (argv[i][length] == '=')) { + int j; + const char *return_string = argv[i] + (length+1); + + for (j=0; j<_PAM_RETURN_VALUES; ++j) { + if (!strcmp(return_string, _pam_token_returns[j])) { + retval = j; + state(pamh, argv[i]); + break; + } + } + break; + } + } + + return retval; +} + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int retval; + const char *user=NULL; + + /* + * authentication requires we know who the user wants to be + */ + retval = pam_get_user(pamh, &user, NULL); + if (retval != PAM_SUCCESS) { + D(("get user returned error: %s", pam_strerror(pamh,retval))); + return retval; + } + if (user == NULL || *user == '\0') { + D(("username not known")); + pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + } + user = NULL; /* clean up */ + + retval = parse_args(PAM_SUCCESS, "auth", pamh, argc, argv); + + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return parse_args(PAM_SUCCESS, "cred", pamh, argc, argv); +} + +/* --- account management functions --- */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return parse_args(PAM_SUCCESS, "acct", pamh, argc, argv); +} + +/* --- password management --- */ + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + if (flags & PAM_PRELIM_CHECK) { + return parse_args(PAM_SUCCESS, "prechauthtok", pamh, argc, argv); + } else { + return parse_args(PAM_SUCCESS, "chauthtok", pamh, argc, argv); + } +} + +/* --- session management --- */ + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc, + const char **argv) +{ + return parse_args(PAM_SUCCESS, "open_session", pamh, argc, argv); +} + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return parse_args(PAM_SUCCESS, "close_session", pamh, argc, argv); +} + +/* end of module definition */ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_permit_modstruct = { + "pam_debug", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; + +#endif diff --git a/Linux-PAM/modules/pam_deny/Makefile b/Linux-PAM/modules/pam_deny/Makefile new file mode 100644 index 00000000..f2a49e1d --- /dev/null +++ b/Linux-PAM/modules/pam_deny/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_deny + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_deny/README b/Linux-PAM/modules/pam_deny/README new file mode 100644 index 00000000..c6b86c79 --- /dev/null +++ b/Linux-PAM/modules/pam_deny/README @@ -0,0 +1,4 @@ +# $Id: README,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# + +this module always fails, it ignores all options. diff --git a/Linux-PAM/modules/pam_deny/pam_deny.c b/Linux-PAM/modules/pam_deny/pam_deny.c new file mode 100644 index 00000000..d1fa42a3 --- /dev/null +++ b/Linux-PAM/modules/pam_deny/pam_deny.c @@ -0,0 +1,81 @@ +/* pam_permit module */ + +/* + * $Id: pam_deny.c,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 + * + */ + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> + +/* --- authentication management functions --- */ + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_AUTH_ERR; +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_CRED_UNAVAIL; +} + +/* --- account management functions --- */ + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_ACCT_EXPIRED; +} + +/* --- password management --- */ + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_AUTHTOK_ERR; +} + +/* --- session management --- */ + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SYSTEM_ERR; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SYSTEM_ERR; +} + +/* end of module definition */ + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_deny_modstruct = { + "pam_deny", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; +#endif diff --git a/Linux-PAM/modules/pam_env/Makefile b/Linux-PAM/modules/pam_env/Makefile new file mode 100644 index 00000000..25856f04 --- /dev/null +++ b/Linux-PAM/modules/pam_env/Makefile @@ -0,0 +1,22 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_env +LOCAL_CONFILE=./pam_env.conf-example +INSTALLED_CONFILE=$(SCONFIGD)/pam_env.conf + +DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" +CFLAGS += $(DEFS) + +MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" +MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) +MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_env/README b/Linux-PAM/modules/pam_env/README new file mode 100644 index 00000000..27d007b9 --- /dev/null +++ b/Linux-PAM/modules/pam_env/README @@ -0,0 +1,72 @@ +# $Date: 2001/04/29 04:17:19 $ +# $Author: hartmans $ +# $Id: README,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# +# This is the configuration file for pam_env, a PAM module to load in +# a configurable list of environment variables for a +# +# The original idea for this came from Andrew G. Morgan ... +#<quote> +# Mmm. Perhaps you might like to write a pam_env module that reads a +# default environment from a file? I can see that as REALLY +# useful... Note it would be an "auth" module that returns PAM_IGNORE +# for the auth part and sets the environment returning PAM_SUCCESS in +# the setcred function... +#</quote> +# +# What I wanted was the REMOTEHOST variable set, purely for selfish +# reasons, and AGM didn't want it added to the SimpleApps login +# program (which is where I added the patch). So, my first concern is +# that variable, from there there are numerous others that might/would +# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER ..... +# +# Of course, these are a different kind of variable than REMOTEHOST in +# that they are things that are likely to be configured by +# administrators rather than set by logging in, how to treat them both +# in the same config file? +# +# Here is my idea: +# +# Each line starts with the variable name, there are then two possible +# options for each variable DEFAULT and OVERRIDE. +# DEFAULT allows and administrator to set the value of the +# variable to some default value, if none is supplied then the empty +# string is assumed. The OVERRIDE option tells pam_env that it should +# enter in its value (overriding the default value) if there is one +# to use. OVERRIDE is not used, "" is assumed and no override will be +# done. +# +# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] +# +# (Possibly non-existent) environment variables may be used in values +# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may +# be used in values using the @{string} syntax. Both the $ and @ +# characters can be backslash escaped to be used as literal values +# values can be delimited with "", escaped " not supported. +# +# +# First, some special variables +# +# Set the REMOTEHOST variable for any hosts that are remote, default +# to "localhost" rather than not being set at all +REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST} +# +# Set the DISPLAY variable if it seems reasonable +DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY} +# +# +# Now some simple variables +# +PAGER DEFAULT=less +MANPAGER DEFAULT=less +LESS DEFAULT="M q e h15 z23 b80" +NNTPSERVER DEFAULT=localhost +PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\ +:/usr/bin:/usr/local/bin/X11:/usr/bin/X11 +# +# silly examples of escaped variables, just to show how they work. +# +DOLLAR DEFAULT=\$ +DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR} +DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST} +ATSIGN DEFAULT="" OVERRIDE=\@ diff --git a/Linux-PAM/modules/pam_env/pam_env.c b/Linux-PAM/modules/pam_env/pam_env.c new file mode 100644 index 00000000..2b7533d0 --- /dev/null +++ b/Linux-PAM/modules/pam_env/pam_env.c @@ -0,0 +1,842 @@ +/* pam_mail module */ + +/* + * $Id: pam_env.c,v 1.1.1.2 2002/09/15 20:08:46 hartmans Exp $ + * + * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31 + * Inspired by Andrew Morgan <morgan@kernel.org>, who also supplied the + * template for this file (via pam_mail) + */ + +#ifndef DEFAULT_CONF_FILE +#define DEFAULT_CONF_FILE "/etc/security/pam_env.conf" +#endif + +#define DEFAULT_ETC_ENVFILE "/etc/environment" +#define DEFAULT_READ_ENVFILE 1 + +#include <security/_pam_aconf.h> + +#include <ctype.h> +#include <errno.h> +#include <pwd.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH /* This is primarily a AUTH_SETCRED module */ +#define PAM_SM_SESSION /* But I like to be friendly */ +#define PAM_SM_PASSWORD /* "" */ +#define PAM_SM_ACCOUNT /* "" */ + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* This little structure makes it easier to keep variables together */ + +typedef struct var { + char *name; + char *value; + char *defval; + char *override; +} VAR; + +#define BUF_SIZE 1024 +#define MAX_ENV 8192 + +#define GOOD_LINE 0 +#define BAD_LINE 100 /* This must be > the largest PAM_* error code */ + +#define DEFINE_VAR 101 +#define UNDEFINE_VAR 102 +#define ILLEGAL_VAR 103 + +static int _assemble_line(FILE *, char *, int); +static int _parse_line(char *, VAR *); +static int _check_var(pam_handle_t *, VAR *); /* This is the real meat */ +static void _clean_var(VAR *); +static int _expand_arg(pam_handle_t *, char **); +static const char * _pam_get_item_byname(pam_handle_t *, const char *); +static int _define_var(pam_handle_t *, VAR *); +static int _undefine_var(pam_handle_t *, VAR *); + +/* This is a flag used to designate an empty string */ +static char quote='Z'; + +/* some syslogging */ + +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-env", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x01 +#define PAM_NEW_CONF_FILE 0x02 +#define PAM_ENV_SILENT 0x04 +#define PAM_NEW_ENV_FILE 0x10 + +static int _pam_parse(int flags, int argc, const char **argv, char **conffile, + char **envfile, int *readenv) +{ + int ctrl=0; + + + /* step through arguments */ + for (; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strncmp(*argv,"conffile=",9)) { + *conffile = x_strdup(9+*argv); + if (*conffile != NULL) { + D(("new Configuration File: %s", *conffile)); + ctrl |= PAM_NEW_CONF_FILE; + } else { + _log_err(LOG_CRIT, + "Configuration file specification missing argument - ignored"); + } + } else if (!strncmp(*argv,"envfile=",8)) { + *envfile = x_strdup(8+*argv); + if (*envfile != NULL) { + D(("new Env File: %s", *envfile)); + ctrl |= PAM_NEW_ENV_FILE; + } else { + _log_err(LOG_CRIT, + "Env file specification missing argument - ignored"); + } + } else if (!strncmp(*argv,"readenv=",8)) + *readenv = atoi(8+*argv); + else + _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + + return ctrl; +} + +static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile) +{ + int retval; + const char *file; + char buffer[BUF_SIZE]; + FILE *conf; + VAR Var, *var=&Var; + + var->name=NULL; var->defval=NULL; var->override=NULL; + D(("Called.")); + + if (ctrl & PAM_NEW_CONF_FILE) { + file = *conffile; + } else { + file = DEFAULT_CONF_FILE; + } + + D(("Config file name is: %s", file)); + + /* + * Lets try to open the config file, parse it and process + * any variables found. + */ + + if ((conf = fopen(file,"r")) == NULL) { + _log_err(LOG_ERR, "Unable to open config file: %s", + strerror(errno)); + return PAM_IGNORE; + } + + /* _pam_assemble_line will provide a complete line from the config file, with all + * comments removed and any escaped newlines fixed up + */ + + while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) { + D(("Read line: %s", buffer)); + + if ((retval = _parse_line(buffer, var)) == GOOD_LINE) { + retval = _check_var(pamh, var); + + if (DEFINE_VAR == retval) { + retval = _define_var(pamh, var); + + } else if (UNDEFINE_VAR == retval) { + retval = _undefine_var(pamh, var); + } + } + if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval + && BAD_LINE != retval && PAM_BAD_ITEM != retval) break; + + _clean_var(var); + + } /* while */ + + (void) fclose(conf); + + /* tidy up */ + _clean_var(var); /* We could have got here prematurely, this is safe though */ + _pam_overwrite(*conffile); + _pam_drop(*conffile); + file = NULL; + D(("Exit.")); + return (retval<0?PAM_ABORT:PAM_SUCCESS); +} + +static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) +{ + int retval=PAM_SUCCESS, i, t; + const char *file; + char buffer[BUF_SIZE], *key, *mark; + FILE *conf; + + if (ctrl & PAM_NEW_ENV_FILE) + file = *env_file; + else + file = DEFAULT_ETC_ENVFILE; + + D(("Env file name is: %s", file)); + + if ((conf = fopen(file,"r")) == NULL) { + D(("Unable to open env file: %s", strerror(errno))); + return PAM_ABORT; + } + + while (_assemble_line(conf, buffer, BUF_SIZE) > 0) { + D(("Read line: %s", buffer)); + key = buffer; + + /* skip leading white space */ + key += strspn(key, " \n\t"); + + /* skip blanks lines and comments */ + if (!key || key[0] == '#') + continue; + + /* skip over "export " if present so we can be compat with + bash type declerations */ + if (strncmp(key, "export ", (size_t) 7) == 0) + key += 7; + + /* now find the end of value */ + mark = key; + while(mark[0] != '\n' && mark[0] != '#' && mark[0] != '\0') + mark++; + if (mark[0] != '\0') + mark[0] = '\0'; + + /* + * sanity check, the key must be alpha-numeric + */ + + for ( i = 0 ; key[i] != '=' && key[i] != '\0' ; i++ ) + if (!isalnum(key[i]) && key[i] != '_') { + D(("key is not alpha numeric - '%s', ignoring", key)); + continue; + } + + /* now we try to be smart about quotes around the value, + but not too smart, we can't get all fancy with escaped + values like bash */ + if (key[i] == '=' && (key[++i] == '\"' || key[i] == '\'')) { + for ( t = i+1 ; key[t] != '\0' ; t++) + if (key[t] != '\"' && key[t] != '\'') + key[i++] = key[t]; + else if (key[t+1] != '\0') + key[i++] = key[t]; + key[i] = '\0'; + } + + /* set the env var, if it fails, we break out of the loop */ + retval = pam_putenv(pamh, key); + if (retval != PAM_SUCCESS) { + D(("error setting env \"%s\"", key)); + break; + } + } + + (void) fclose(conf); + + /* tidy up */ + _pam_overwrite(*env_file); + _pam_drop(*env_file); + file = NULL; + D(("Exit.")); + return (retval<0?PAM_IGNORE:PAM_SUCCESS); +} + +/* + * This is where we read a line of the PAM config file. The line may be + * preceeded by lines of comments and also extended with "\\\n" + */ + +static int _assemble_line(FILE *f, char *buffer, int buf_len) +{ + char *p = buffer; + char *s, *os; + int used = 0; + + /* loop broken with a 'break' when a non-'\\n' ended line is read */ + + D(("called.")); + for (;;) { + if (used >= buf_len) { + /* Overflow */ + D(("_assemble_line: overflow")); + return -1; + } + if (fgets(p, buf_len - used, f) == NULL) { + if (used) { + /* Incomplete read */ + return -1; + } else { + /* EOF */ + return 0; + } + } + + /* skip leading spaces --- line may be blank */ + + s = p + strspn(p, " \n\t"); + if (*s && (*s != '#')) { + os = s; + + /* + * we are only interested in characters before the first '#' + * character + */ + + while (*s && *s != '#') + ++s; + if (*s == '#') { + *s = '\0'; + used += strlen(os); + break; /* the line has been read */ + } + + s = os; + + /* + * Check for backslash by scanning back from the end of + * the entered line, the '\n' has been included since + * normally a line is terminated with this + * character. fgets() should only return one though! + */ + + s += strlen(s); + while (s > os && ((*--s == ' ') || (*s == '\t') + || (*s == '\n'))); + + /* check if it ends with a backslash */ + if (*s == '\\') { + *s = '\0'; /* truncate the line here */ + used += strlen(os); + p = s; /* there is more ... */ + } else { + /* End of the line! */ + used += strlen(os); + break; /* this is the complete line */ + } + + } else { + /* Nothing in this line */ + /* Don't move p */ + } + } + + return used; +} + +static int _parse_line(char *buffer, VAR *var) +{ + /* + * parse buffer into var, legal syntax is + * VARIABLE [DEFAULT=[[string]] [OVERRIDE=[value]] + * + * Any other options defined make this a bad line, + * error logged and no var set + */ + + int length, quoteflg=0; + char *ptr, **valptr, *tmpptr; + + D(("Called buffer = <%s>", buffer)); + + length = strcspn(buffer," \t\n"); + + if ((var->name = malloc(length + 1)) == NULL) { + _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1); + return PAM_BUF_ERR; + } + + /* + * The first thing on the line HAS to be the variable name, + * it may be the only thing though. + */ + strncpy(var->name, buffer, length); + var->name[length] = '\0'; + D(("var->name = <%s>, length = %d", var->name, length)); + + /* + * Now we check for arguments, we only support two kinds and ('cause I am lazy) + * each one can actually be listed any number of times + */ + + ptr = buffer+length; + while ((length = strspn(ptr, " \t")) > 0) { + ptr += length; /* remove leading whitespace */ + D((ptr)); + if (strncmp(ptr,"DEFAULT=",8) == 0) { + ptr+=8; + D(("Default arg found: <%s>", ptr)); + valptr=&(var->defval); + } else if (strncmp(ptr, "OVERRIDE=", 9) == 0) { + ptr+=9; + D(("Override arg found: <%s>", ptr)); + valptr=&(var->override); + } else { + D(("Unrecognized options: <%s> - ignoring line", ptr)); + _log_err(LOG_ERR, "Unrecognized Option: %s - ignoring line", ptr); + return BAD_LINE; + } + + if ('"' != *ptr) { /* Escaped quotes not supported */ + length = strcspn(ptr, " \t\n"); + tmpptr = ptr+length; + } else { + tmpptr = strchr(++ptr, '"'); + if (!tmpptr) { + D(("Unterminated quoted string: %s", ptr-1)); + _log_err(LOG_ERR, "Unterminated quoted string: %s", ptr-1); + return BAD_LINE; + } + length = tmpptr - ptr; + if (*++tmpptr && ' ' != *tmpptr && '\t' != *tmpptr && '\n' != *tmpptr) { + D(("Quotes must cover the entire string: <%s>", ptr)); + _log_err(LOG_ERR, "Quotes must cover the entire string: <%s>", ptr); + return BAD_LINE; + } + quoteflg++; + } + if (length) { + if ((*valptr = malloc(length + 1)) == NULL) { + D(("Couldn't malloc %d bytes", length+1)); + _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1); + return PAM_BUF_ERR; + } + (void)strncpy(*valptr,ptr,length); + (*valptr)[length]='\0'; + } else if (quoteflg--) { + *valptr = "e; /* a quick hack to handle the empty string */ + } + ptr = tmpptr; /* Start the search where we stopped */ + } /* while */ + + /* + * The line is parsed, all is well. + */ + + D(("Exit.")); + ptr = NULL; tmpptr = NULL; valptr = NULL; + return GOOD_LINE; +} + +static int _check_var(pam_handle_t *pamh, VAR *var) +{ + /* + * Examine the variable and determine what action to take. + * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take + * or a PAM_* error code if passed back from other routines + * + * if no DEFAULT provided, the empty string is assumed + * if no OVERRIDE provided, the empty string is assumed + * if DEFAULT= and OVERRIDE evaluates to the empty string, + * this variable should be undefined + * if DEFAULT="" and OVERRIDE evaluates to the empty string, + * this variable should be defined with no value + * if OVERRIDE=value and value turns into the empty string, DEFAULT is used + * + * If DEFINE_VAR is to be returned, the correct value to define will + * be pointed to by var->value + */ + + int retval; + + D(("Called.")); + + /* + * First thing to do is to expand any arguments, but only + * if they are not the special quote values (cause expand_arg + * changes memory). + */ + + if (var->defval && ("e != var->defval) && + ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { + return retval; + } + if (var->override && ("e != var->override) && + ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { + return retval; + } + + /* Now its easy */ + + if (var->override && *(var->override) && "e != var->override) { + /* if there is a non-empty string in var->override, we use it */ + D(("OVERRIDE variable <%s> being used: <%s>", var->name, var->override)); + var->value = var->override; + retval = DEFINE_VAR; + } else { + + var->value = var->defval; + if ("e == var->defval) { + /* + * This means that the empty string was given for defval value + * which indicates that a variable should be defined with no value + */ + *var->defval = '\0'; + D(("An empty variable: <%s>", var->name)); + retval = DEFINE_VAR; + } else if (var->defval) { + D(("DEFAULT variable <%s> being used: <%s>", var->name, var->defval)); + retval = DEFINE_VAR; + } else { + D(("UNDEFINE variable <%s>", var->name)); + retval = UNDEFINE_VAR; + } + } + + D(("Exit.")); + return retval; +} + +static int _expand_arg(pam_handle_t *pamh, char **value) +{ + const char *orig=*value, *tmpptr=NULL; + char *ptr; /* + * Sure would be nice to use tmpptr but it needs to be + * a constant so that the compiler will shut up when I + * call pam_getenv and _pam_get_item_byname -- sigh + */ + + /* No unexpanded variable can be bigger than BUF_SIZE */ + char type, tmpval[BUF_SIZE]; + + /* I know this shouldn't be hard-coded but it's so much easier this way */ + char tmp[MAX_ENV]; + + D(("Remember to initialize tmp!")); + memset(tmp, 0, MAX_ENV); + + /* + * (possibly non-existent) environment variables can be used as values + * by prepending a "$" and wrapping in {} (ie: ${HOST}), can escape with "\" + * (possibly non-existent) PAM items can be used as values + * by prepending a "@" and wrapping in {} (ie: @{PAM_RHOST}, can escape + * + */ + D(("Expanding <%s>",orig)); + while (*orig) { /* while there is some input to deal with */ + if ('\\' == *orig) { + ++orig; + if ('$' != *orig && '@' != *orig) { + D(("Unrecognized escaped character: <%c> - ignoring", *orig)); + _log_err(LOG_ERR, "Unrecognized escaped character: <%c> - ignoring", + *orig); + } else if ((strlen(tmp) + 1) < MAX_ENV) { + tmp[strlen(tmp)] = *orig++; /* Note the increment */ + } else { + /* is it really a good idea to try to log this? */ + D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); + _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", + tmp, tmpptr); + } + continue; + } + if ('$' == *orig || '@' == *orig) { + if ('{' != *(orig+1)) { + D(("Expandable variables must be wrapped in {}" + " <%s> - ignoring", orig)); + _log_err(LOG_ERR, "Expandable variables must be wrapped in {}" + " <%s> - ignoring", orig); + if ((strlen(tmp) + 1) < MAX_ENV) { + tmp[strlen(tmp)] = *orig++; /* Note the increment */ + } + continue; + } else { + D(("Expandable argument: <%s>", orig)); + type = *orig; + orig+=2; /* skip the ${ or @{ characters */ + ptr = strchr(orig, '}'); + if (ptr) { + *ptr++ = '\0'; + } else { + D(("Unterminated expandable variable: <%s>", orig-2)); + _log_err(LOG_ERR, "Unterminated expandable variable: <%s>", orig-2); + return PAM_ABORT; + } + strncpy(tmpval, orig, sizeof(tmpval)); + tmpval[sizeof(tmpval)-1] = '\0'; + orig=ptr; + /* + * so, we know we need to expand tmpval, it is either + * an environment variable or a PAM_ITEM. type will tell us which + */ + switch (type) { + + case '$': + D(("Expanding env var: <%s>",tmpval)); + tmpptr = pam_getenv(pamh, tmpval); + D(("Expanded to <%s>", tmpptr)); + break; + + case '@': + D(("Expanding pam item: <%s>",tmpval)); + tmpptr = _pam_get_item_byname(pamh, tmpval); + D(("Expanded to <%s>", tmpptr)); + break; + + default: + D(("Impossible error, type == <%c>", type)); + _log_err(LOG_CRIT, "Impossible error, type == <%c>", type); + return PAM_ABORT; + } /* switch */ + + if (tmpptr) { + if ((strlen(tmp) + strlen(tmpptr)) < MAX_ENV) { + strcat(tmp, tmpptr); + } else { + /* is it really a good idea to try to log this? */ + D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); + _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); + } + } + } /* if ('{' != *orig++) */ + } else { /* if ( '$' == *orig || '@' == *orig) */ + if ((strlen(tmp) + 1) < MAX_ENV) { + tmp[strlen(tmp)] = *orig++; /* Note the increment */ + } else { + /* is it really a good idea to try to log this? */ + D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); + _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); + } + } + } /* for (;*orig;) */ + + if (strlen(tmp) > strlen(*value)) { + free(*value); + if ((*value = malloc(strlen(tmp) +1)) == NULL) { + D(("Couldn't malloc %d bytes for expanded var", strlen(tmp)+1)); + _log_err(LOG_ERR,"Couldn't malloc %d bytes for expanded var", + strlen(tmp)+1); + return PAM_BUF_ERR; + } + } + strcpy(*value, tmp); + memset(tmp,'\0',sizeof(tmp)); + D(("Exit.")); + + return PAM_SUCCESS; +} + +static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) +{ + /* + * This function just allows me to use names as given in the config + * file and translate them into the appropriate PAM_ITEM macro + */ + + int item; + const char *itemval; + + D(("Called.")); + if (strcmp(name, "PAM_USER") == 0) { + item = PAM_USER; + } else if (strcmp(name, "PAM_USER_PROMPT") == 0) { + item = PAM_USER_PROMPT; + } else if (strcmp(name, "PAM_TTY") == 0) { + item = PAM_TTY; + } else if (strcmp(name, "PAM_RUSER") == 0) { + item = PAM_RUSER; + } else if (strcmp(name, "PAM_RHOST") == 0) { + item = PAM_RHOST; + } else { + D(("Unknown PAM_ITEM: <%s>", name)); + _log_err(LOG_ERR, "Unknown PAM_ITEM: <%s>", name); + return NULL; + } + + if (pam_get_item(pamh, item, (const void **)&itemval) != PAM_SUCCESS) { + D(("pam_get_item failed")); + return NULL; /* let pam_get_item() log the error */ + } + D(("Exit.")); + return itemval; +} + +static int _define_var(pam_handle_t *pamh, VAR *var) +{ + /* We have a variable to define, this is a simple function */ + + char *envvar; + int size, retval=PAM_SUCCESS; + + D(("Called.")); + size = strlen(var->name)+strlen(var->value)+2; + if ((envvar = malloc(size)) == NULL) { + D(("Malloc fail, size = %d", size)); + _log_err(LOG_ERR, "Malloc fail, size = %d", size); + return PAM_BUF_ERR; + } + (void) sprintf(envvar,"%s=%s",var->name,var->value); + retval = pam_putenv(pamh, envvar); + free(envvar); envvar=NULL; + D(("Exit.")); + return retval; +} + +static int _undefine_var(pam_handle_t *pamh, VAR *var) +{ + /* We have a variable to undefine, this is a simple function */ + + D(("Called and exit.")); + return pam_putenv(pamh, var->name); +} + +static void _clean_var(VAR *var) +{ + if (var->name) { + free(var->name); + } + if (var->defval && ("e != var->defval)) { + free(var->defval); + } + if (var->override && ("e != var->override)) { + free(var->override); + } + var->name = NULL; + var->value = NULL; /* never has memory specific to it */ + var->defval = NULL; + var->override = NULL; + return; +} + + + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return PAM_IGNORE; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; + char *conf_file=NULL, *env_file=NULL; + + /* + * this module sets environment variables read in from a file + */ + + D(("Called.")); + ctrl = _pam_parse(flags, argc, argv, &conf_file, &env_file, &readenv); + + retval = _parse_config_file(pamh, ctrl, &conf_file); + + if(readenv) + _parse_env_file(pamh, ctrl, &env_file); + + /* indicate success or failure */ + + D(("Exit.")); + return retval; +} + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + _log_err(LOG_NOTICE, "pam_sm_acct_mgmt called inappropriatly"); + return PAM_SERVICE_ERR; +} + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; + char *conf_file=NULL, *env_file=NULL; + + /* + * this module sets environment variables read in from a file + */ + + D(("Called.")); + ctrl = _pam_parse(flags, argc, argv, &conf_file, &env_file, &readenv); + + retval = _parse_config_file(pamh, ctrl, &conf_file); + + if(readenv) + _parse_env_file(pamh, ctrl, &env_file); + + /* indicate success or failure */ + + D(("Exit.")); + return retval; +} + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc, + const char **argv) +{ + D(("Called and Exit")); + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + _log_err(LOG_NOTICE, "pam_sm_chauthtok called inappropriatly"); + return PAM_SERVICE_ERR; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_env_modstruct = { + "pam_env", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_env/pam_env.conf-example b/Linux-PAM/modules/pam_env/pam_env.conf-example new file mode 100644 index 00000000..fa4e0b84 --- /dev/null +++ b/Linux-PAM/modules/pam_env/pam_env.conf-example @@ -0,0 +1,72 @@ +# $Date: 2001/04/29 04:17:19 $ +# $Author: hartmans $ +# $Id: pam_env.conf-example,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# +# This is the configuration file for pam_env, a PAM module to load in +# a configurable list of environment variables for a +# +# The original idea for this came from Andrew G. Morgan ... +#<quote> +# Mmm. Perhaps you might like to write a pam_env module that reads a +# default environment from a file? I can see that as REALLY +# useful... Note it would be an "auth" module that returns PAM_IGNORE +# for the auth part and sets the environment returning PAM_SUCCESS in +# the setcred function... +#</quote> +# +# What I wanted was the REMOTEHOST variable set, purely for selfish +# reasons, and AGM didn't want it added to the SimpleApps login +# program (which is where I added the patch). So, my first concern is +# that variable, from there there are numerous others that might/would +# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER ..... +# +# Of course, these are a different kind of variable than REMOTEHOST in +# that they are things that are likely to be configured by +# administrators rather than set by logging in, how to treat them both +# in the same config file? +# +# Here is my idea: +# +# Each line starts with the variable name, there are then two possible +# options for each variable DEFAULT and OVERRIDE. +# DEFAULT allows and administrator to set the value of the +# variable to some default value, if none is supplied then the empty +# string is assumed. The OVERRIDE option tells pam_env that it should +# enter in its value (overriding the default value) if there is one +# to use. OVERRIDE is not used, "" is assumed and no override will be +# done. +# +# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] +# +# (Possibly non-existent) environment variables may be used in values +# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may +# be used in values using the @{string} syntax. Both the $ and @ +# characters can be backslash escaped to be used as literal values +# values can be delimited with "", escaped " not supported. +# +# +# First, some special variables +# +# Set the REMOTEHOST variable for any hosts that are remote, default +# to "localhost" rather than not being set at all +#REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST} +# +# Set the DISPLAY variable if it seems reasonable +#DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY} +# +# +# Now some simple variables +# +#PAGER DEFAULT=less +#MANPAGER DEFAULT=less +#LESS DEFAULT="M q e h15 z23 b80" +#NNTPSERVER DEFAULT=localhost +#PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\ +#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11 +# +# silly examples of escaped variables, just to show how they work. +# +#DOLLAR DEFAULT=\$ +#DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR} +#DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST} +#ATSIGN DEFAULT="" OVERRIDE=\@ diff --git a/Linux-PAM/modules/pam_filter/.upperLOWER b/Linux-PAM/modules/pam_filter/.upperLOWER new file mode 100644 index 00000000..2531b468 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/.upperLOWER @@ -0,0 +1 @@ +a test filter that transposes upper and lower case characters diff --git a/Linux-PAM/modules/pam_filter/Makefile b/Linux-PAM/modules/pam_filter/Makefile new file mode 100644 index 00000000..caad06c7 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/Makefile @@ -0,0 +1,126 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 +# + +ifeq ($(OS),solaris) + +include ../dont_makefile + +else + +include ../../Make.Rules + +TITLE=pam_filter +FILTERS=upperLOWER +FILTERSDIR=$(SECUREDIR)/pam_filter +export FILTERSDIR + +CFLAGS += -Iinclude + +LIBSRC = $(TITLE).c +LIBOBJ = $(TITLE).o +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif + +ifdef STATIC +LIBSTATIC = lib$(TITLE).o +endif + +####################### don't edit below ####################### + +# +# this is where we compile this module +# + +all: dirs $(LIBSHARED) $(LIBSTATIC) register filters + +dirs: + if [ ! -r include/security ]; then ln -sf . include/security ; fi +ifdef DYNAMIC + $(MKDIR) ./dynamic +endif +ifdef STATIC + $(MKDIR) ./static +endif + +register: +ifdef STATIC + ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +endif + +filters: + @for i in $(FILTERS) ; do \ + if [ -d $$i ]; then \ + $(MAKE) -C $$i all ; \ + fi ; \ + done + + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) +endif + +ifdef DYNAMIC +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) +endif + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) +endif + +ifdef STATIC +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) +endif + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + rm -f $(FAKEROOT)$(INCLUDED)/pam_filter.h + @for i in $(FILTERS) ; do \ + if [ -d $$i ]; then \ + $(MAKE) -C $$i remove ; \ + fi ; \ + done + +install: all + @for i in $(FILTERS) ; do \ + if [ -d $$i ]; then \ + $(MAKE) -C $$i install ; \ + fi ; \ + done + $(MKDIR) $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + $(MKDIR) $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/pam_filter.h $(FAKEROOT)$(INCLUDED) + +clean: + @for i in $(FILTERS) ; do \ + if [ -d $$i ]; then \ + $(MAKE) -C $$i clean ; \ + fi ; \ + done + rm -f $(LIBSHARED) $(LIBOBJD) $(LIBOBJS) core *~ + rm -f include/security + rm -fr dynamic static + rm -f *.a *.o *.so *.bak + +endif diff --git a/Linux-PAM/modules/pam_filter/README b/Linux-PAM/modules/pam_filter/README new file mode 100644 index 00000000..64bac608 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/README @@ -0,0 +1,94 @@ +# +# $Id: README,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# +# This describes the behavior of this module with respect to the +# /etc/pam.conf file. +# +# writen by Andrew Morgan <morgan@parc.power.net> +# + +This module is intended to be a platform for providing access to all +of the input/output that passes between the user and the application. +It is only suitable for tty-based and (stdin/stdout) applications. And +is only known to work on Linux based systems. + +The action of the module is dictated by the arguments it is given in +the pam.conf file. + +recognized flags are: + + debug print some information to syslog(3) + + new_term set the PAM_TTY item to the new filtered + terminal (the default is to set it + to be that of the users terminal) + + non_term don't try to set the PAM_TTY item + + run1/run2 these arguments indicate that the + module should separate the application + from the user and insert a filter + program between them. The pathname of + the filter program follows the 'runN' + argument. Arguments that follow this + pathname are passed as arguments to + the filter program. + + The distinction between run1 and run2 + is which of the two functions of + the given management-type triggers the + execution of the indicated filter. + + type: run1 run2 + ----- ---- ---- + + auth pam_sm_authenticate pam_sm_setcred + + account [ pam_sm_acct_mgmt (either is good) ] + + session pam_sm_open_session pam_sm_close_session + + password pam_sm_chauthtok/PRELIM pam_sm_chauthtok/UPDATE + +Note, in the case of 'password' PRELIM/UPDATE indicates which of the +two calls to pam_sm_chauthtok from libpam (not the application) will +trigger the filter. + +What a filter program should expect: +------------------------------------ + +Definitions for filter programs (which may be locally designed) are +contained in the <security/pam_filter.h> file. + +Arguments are not passed to the filter on the command line, since this +is plainly visible when a user types 'ps -a'. Instead they are passed +as the filter's environment. Other information is passed in this way +too. + +Here is a list of the environment variables that a filter should +expect: + + ARGS="filter_path_name argument list" + SERVICE="service_name" (as it appears in /etc/pam.conf) + USER="username" + TYPE="module_fn" (the name of the function in pam_filter.so + that invoked the filter) + +[This list is likely to grow. If you want something added, email me!] + +Among other things this module is intended to provide a useful means +of logging the activity of users in as discrete a manner as possible. + +Existing filters: +----------------- + +Currently, there is a single supplied filter (upperLOWER). The effect +of using this filter is to transpose upper and lower case letters +between the user and the application. This is really annoying when you +try the 'xsh' example application! ;) + +TODO: provide more filters... + Decide if providing stderr interception is really overkill. + +Andrew G. Morgan <morgan@parc.power.net> 1996/5/27 + diff --git a/Linux-PAM/modules/pam_filter/include/pam_filter.h b/Linux-PAM/modules/pam_filter/include/pam_filter.h new file mode 100644 index 00000000..f189c911 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/include/pam_filter.h @@ -0,0 +1,32 @@ +/* + * $Id: pam_filter.h,v 1.1.1.1 2001/04/29 04:17:20 hartmans Exp $ + * + * this file is associated with the Linux-PAM filter module. + * it was written by Andrew G. Morgan <morgan@linux.kernel.org> + * + */ + +#ifndef PAM_FILTER_H +#define PAM_FILTER_H + +#include <sys/file.h> + +/* + * this will fail if there is some problem with these file descriptors + * being allocated by the pam_filter Linux-PAM module. The numbers + * here are thought safe, but the filter developer should use the + * macros, as these numbers are subject to change. + * + * The APPXXX_FILENO file descriptors are the STDIN/OUT/ERR_FILENO of the + * application. The filter uses the STDIN/OUT/ERR_FILENO's to converse + * with the user, passes (modified) user input to the application via + * APPIN_FILENO, and receives application output from APPOUT_FILENO/ERR. + */ + +#define APPIN_FILENO 3 /* write here to give application input */ +#define APPOUT_FILENO 4 /* read here to get application output */ +#define APPERR_FILENO 5 /* read here to get application errors */ + +#define APPTOP_FILE 6 /* used by select */ + +#endif diff --git a/Linux-PAM/modules/pam_filter/pam_filter.c b/Linux-PAM/modules/pam_filter/pam_filter.c new file mode 100644 index 00000000..0ddd3711 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/pam_filter.c @@ -0,0 +1,735 @@ +/* + * $Id: pam_filter.c,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ + * + * written by Andrew Morgan <morgan@transmeta.com> with much help from + * Richard Stevens' UNIX Network Programming book. + */ + +#include <security/_pam_aconf.h> + +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <termio.h> + +#include <signal.h> + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/pam_filter.h> + +/* ------ some tokens used for convenience throughout this file ------- */ + +#define FILTER_DEBUG 01 +#define FILTER_RUN1 02 +#define FILTER_RUN2 04 +#define NEW_TERM 010 +#define NON_TERM 020 + +/* -------------------------------------------------------------------- */ + +/* log errors */ + +#include <stdarg.h> + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pam_filter", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +#define TERMINAL_LEN 12 + +static int master(char *terminal) +/* + * try to open all of the terminals in sequence return first free one, + * or -1 + */ +{ + const char ptys[] = "pqrs", *pty = ptys; + const char hexs[] = "0123456789abcdef", *hex; + struct stat tstat; + int fd; + + strcpy(terminal, "/dev/pty??"); + + while (*pty) { /* step through four types */ + terminal[8] = *pty++; + terminal[9] = '0'; + if (stat(terminal,&tstat) < 0) { + _pam_log(LOG_WARNING, "unknown pseudo terminal; %s", terminal); + break; + } + for (hex = hexs; *hex; ) { /* step through 16 of these */ + terminal[9] = *hex++; + if ((fd = open(terminal, O_RDWR)) >= 0) { + return fd; + } + } + } + + /* no terminal found */ + + return -1; +} + +static int process_args(pam_handle_t *pamh + , int argc, const char **argv, const char *type + , char ***evp, const char **filtername) +{ + int ctrl=0; + + while (argc-- > 0) { + if (strcmp("debug",*argv) == 0) { + ctrl |= FILTER_DEBUG; + } else if (strcmp("new_term",*argv) == 0) { + ctrl |= NEW_TERM; + } else if (strcmp("non_term",*argv) == 0) { + ctrl |= NON_TERM; + } else if (strcmp("run1",*argv) == 0) { + ctrl |= FILTER_RUN1; + if (argc <= 0) { + _pam_log(LOG_ALERT,"no run filter supplied"); + } else + break; + } else if (strcmp("run2",*argv) == 0) { + ctrl |= FILTER_RUN2; + if (argc <= 0) { + _pam_log(LOG_ALERT,"no run filter supplied"); + } else + break; + } else { + _pam_log(LOG_ERR, "unrecognized option: %s (ignored)", *argv); + } + ++argv; /* step along list */ + } + + if (argc < 0) { + /* there was no reference to a filter */ + *filtername = NULL; + *evp = NULL; + } else { + char **levp; + const char *tmp; + int i,size; + + *filtername = *++argv; + if (ctrl & FILTER_DEBUG) { + _pam_log(LOG_DEBUG,"will run filter %s\n", *filtername); + } + + levp = (char **) malloc(5*sizeof(char *)); + if (levp == NULL) { + _pam_log(LOG_CRIT,"no memory for environment of filter"); + return -1; + } + + for (size=i=0; i<argc; ++i) { + size += strlen(argv[i])+1; + } + + /* the "ARGS" variable */ + +#define ARGS_OFFSET 5 /* sizeof('ARGS='); */ +#define ARGS_NAME "ARGS=" + + size += ARGS_OFFSET; + + levp[0] = (char *) malloc(size); + if (levp[0] == NULL) { + _pam_log(LOG_CRIT,"no memory for filter arguments"); + if (levp) { + free(levp); + } + return -1; + } + + strncpy(levp[0],ARGS_NAME,ARGS_OFFSET); + for (i=0,size=ARGS_OFFSET; i<argc; ++i) { + strcpy(levp[0]+size, argv[i]); + size += strlen(argv[i]); + levp[0][size++] = ' '; + } + levp[0][--size] = '\0'; /* <NUL> terminate */ + + /* the "SERVICE" variable */ + +#define SERVICE_OFFSET 8 /* sizeof('SERVICE='); */ +#define SERVICE_NAME "SERVICE=" + + pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp); + size = SERVICE_OFFSET+strlen(tmp); + + levp[1] = (char *) malloc(size+1); + if (levp[1] == NULL) { + _pam_log(LOG_CRIT,"no memory for service name"); + if (levp) { + free(levp[0]); + free(levp); + } + return -1; + } + + strncpy(levp[1],SERVICE_NAME,SERVICE_OFFSET); + strcpy(levp[1]+SERVICE_OFFSET, tmp); + levp[1][size] = '\0'; /* <NUL> terminate */ + + /* the "USER" variable */ + +#define USER_OFFSET 5 /* sizeof('USER='); */ +#define USER_NAME "USER=" + + pam_get_user(pamh, &tmp, NULL); + if (tmp == NULL) { + tmp = "<unknown>"; + } + size = USER_OFFSET+strlen(tmp); + + levp[2] = (char *) malloc(size+1); + if (levp[2] == NULL) { + _pam_log(LOG_CRIT,"no memory for user's name"); + if (levp) { + free(levp[1]); + free(levp[0]); + free(levp); + } + return -1; + } + + strncpy(levp[2],USER_NAME,USER_OFFSET); + strcpy(levp[2]+USER_OFFSET, tmp); + levp[2][size] = '\0'; /* <NUL> terminate */ + + /* the "USER" variable */ + +#define TYPE_OFFSET 5 /* sizeof('TYPE='); */ +#define TYPE_NAME "TYPE=" + + size = TYPE_OFFSET+strlen(type); + + levp[3] = (char *) malloc(size+1); + if (levp[3] == NULL) { + _pam_log(LOG_CRIT,"no memory for type"); + if (levp) { + free(levp[2]); + free(levp[1]); + free(levp[0]); + free(levp); + } + return -1; + } + + strncpy(levp[3],TYPE_NAME,TYPE_OFFSET); + strcpy(levp[3]+TYPE_OFFSET, type); + levp[3][size] = '\0'; /* <NUL> terminate */ + + levp[4] = NULL; /* end list */ + + *evp = levp; + } + + if ((ctrl & FILTER_DEBUG) && *filtername) { + char **e; + + _pam_log(LOG_DEBUG,"filter[%s]: %s",type,*filtername); + _pam_log(LOG_DEBUG,"environment:"); + for (e=*evp; e && *e; ++e) { + _pam_log(LOG_DEBUG," %s",*e); + } + } + + return ctrl; +} + +static void free_evp(char *evp[]) +{ + int i; + + if (evp) + for (i=0; i<4; ++i) { + if (evp[i]) + free(evp[i]); + } + free(evp); +} + +static int set_filter(pam_handle_t *pamh, int flags, int ctrl + , const char **evp, const char *filtername) +{ + int status=-1; + char terminal[TERMINAL_LEN]; + struct termio stored_mode; /* initial terminal mode settings */ + int fd[2], child=0, child2=0, aterminal; + + if (filtername == NULL || *filtername != '/') { + _pam_log(LOG_ALERT, "filtername not permitted; require full path"); + return PAM_ABORT; + } + + if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) { + aterminal = 0; + } else { + aterminal = 1; + } + + if (aterminal) { + + /* open the master pseudo terminal */ + + fd[0] = master(terminal); + if (fd[0] < 0) { + _pam_log(LOG_CRIT,"no master terminal"); + return PAM_AUTH_ERR; + } + + /* set terminal into raw mode.. remember old mode so that we can + revert to it after the child has quit. */ + + /* this is termio terminal handling... */ + + if (ioctl(STDIN_FILENO, TCGETA, (char *) &stored_mode ) < 0) { + /* in trouble, so close down */ + close(fd[0]); + _pam_log(LOG_CRIT, "couldn't copy terminal mode"); + return PAM_ABORT; + } else { + struct termio t_mode = stored_mode; + + t_mode.c_iflag = 0; /* no input control */ + t_mode.c_oflag &= ~OPOST; /* no ouput post processing */ + + /* no signals, canonical input, echoing, upper/lower output */ + t_mode.c_lflag &= ~(ISIG|ICANON|ECHO|XCASE); + t_mode.c_cflag &= ~(CSIZE|PARENB); /* no parity */ + t_mode.c_cflag |= CS8; /* 8 bit chars */ + + t_mode.c_cc[VMIN] = 1; /* number of chars to satisfy a read */ + t_mode.c_cc[VTIME] = 0; /* 0/10th second for chars */ + + if (ioctl(STDIN_FILENO, TCSETA, (char *) &t_mode) < 0) { + close(fd[0]); + _pam_log(LOG_WARNING, "couldn't put terminal in RAW mode"); + return PAM_ABORT; + } + + /* + * NOTE: Unlike the stream socket case here the child + * opens the slave terminal as fd[1] *after* the fork... + */ + } + } else { + + /* + * not a terminal line so just open a stream socket fd[0-1] + * both set... + */ + + if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { + _pam_log(LOG_CRIT,"couldn't open a stream pipe"); + return PAM_ABORT; + } + } + + /* start child process */ + + if ( (child = fork()) < 0 ) { + + _pam_log(LOG_WARNING,"first fork failed"); + if (aterminal) { + (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); + } + + return PAM_AUTH_ERR; + } + + if ( child == 0 ) { /* child process *is* application */ + + if (aterminal) { + + /* close the controlling tty */ + +#if defined(__hpux) && defined(O_NOCTTY) + int t = open("/dev/tty", O_RDWR|O_NOCTTY); +#else + int t = open("/dev/tty",O_RDWR); + if (t > 0) { + (void) ioctl(t, TIOCNOTTY, NULL); + close(t); + } +#endif /* defined(__hpux) && defined(O_NOCTTY) */ + + /* make this process it's own process leader */ + if (setsid() == -1) { + _pam_log(LOG_WARNING,"child cannot become new session"); + return PAM_ABORT; + } + + /* find slave's name */ + terminal[5] = 't'; /* want to open slave terminal */ + fd[1] = open(terminal, O_RDWR); + close(fd[0]); /* process is the child -- uses line fd[1] */ + + if (fd[1] < 0) { + _pam_log(LOG_WARNING,"cannot open slave terminal; %s" + ,terminal); + return PAM_ABORT; + } + + /* initialize the child's terminal to be the way the + parent's was before we set it into RAW mode */ + + if (ioctl(fd[1], TCSETA, (char *) &stored_mode) < 0) { + _pam_log(LOG_WARNING,"cannot set slave terminal mode; %s" + ,terminal); + close(fd[1]); + return PAM_ABORT; + } + + } else { + + /* nothing to do for a simple stream socket */ + + } + + /* re-assign the stdin/out to fd[1] <- (talks to filter). */ + + if ( dup2(fd[1],STDIN_FILENO) != STDIN_FILENO || + dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO || + dup2(fd[1],STDERR_FILENO) != STDERR_FILENO ) { + _pam_log(LOG_WARNING + ,"unable to re-assign STDIN/OUT/ERR...'s"); + close(fd[1]); + return PAM_ABORT; + } + + /* make sure that file descriptors survive 'exec's */ + + if ( fcntl(STDIN_FILENO, F_SETFD, 0) || + fcntl(STDOUT_FILENO,F_SETFD, 0) || + fcntl(STDERR_FILENO,F_SETFD, 0) ) { + _pam_log(LOG_WARNING + ,"unable to re-assign STDIN/OUT/ERR...'s"); + return PAM_ABORT; + } + + /* now the user input is read from the parent/filter: forget fd */ + + close(fd[1]); + + /* the current process is now aparently working with filtered + stdio/stdout/stderr --- success! */ + + return PAM_SUCCESS; + } + + /* + * process is the parent here. So we can close the application's + * input/output + */ + + close(fd[1]); + + /* Clear out passwords... there is a security problem here in + * that this process never executes pam_end. Consequently, any + * other sensitive data in this process is *not* explicitly + * overwritten, before the process terminates */ + + (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); + (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); + + /* fork a copy of process to run the actual filter executable */ + + if ( (child2 = fork()) < 0 ) { + + _pam_log(LOG_WARNING,"filter fork failed"); + child2 = 0; + + } else if ( child2 == 0 ) { /* exec the child filter */ + + if ( dup2(fd[0],APPIN_FILENO) != APPIN_FILENO || + dup2(fd[0],APPOUT_FILENO) != APPOUT_FILENO || + dup2(fd[0],APPERR_FILENO) != APPERR_FILENO ) { + _pam_log(LOG_WARNING + ,"unable to re-assign APPIN/OUT/ERR...'s"); + close(fd[0]); + exit(1); + } + + /* make sure that file descriptors survive 'exec's */ + + if ( fcntl(APPIN_FILENO, F_SETFD, 0) == -1 || + fcntl(APPOUT_FILENO,F_SETFD, 0) == -1 || + fcntl(APPERR_FILENO,F_SETFD, 0) == -1 ) { + _pam_log(LOG_WARNING + ,"unable to retain APPIN/OUT/ERR...'s"); + close(APPIN_FILENO); + close(APPOUT_FILENO); + close(APPERR_FILENO); + exit(1); + } + + /* now the user input is read from the parent through filter */ + + execle(filtername, "<pam_filter>", NULL, evp); + + /* getting to here is an error */ + + _pam_log(LOG_ALERT, "filter: %s, not executable", filtername); + + } else { /* wait for either of the two children to exit */ + + while (child && child2) { /* loop if there are two children */ + int lstatus=0; + int chid; + + chid = wait(&lstatus); + if (chid == child) { + + if (WIFEXITED(lstatus)) { /* exited ? */ + status = WEXITSTATUS(lstatus); + } else if (WIFSIGNALED(lstatus)) { /* killed ? */ + status = -1; + } else + continue; /* just stopped etc.. */ + child = 0; /* the child has exited */ + + } else if (chid == child2) { + /* + * if the filter has exited. Let the child die + * naturally below + */ + if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus)) + child2 = 0; + } else { + + _pam_log(LOG_ALERT + ,"programming error <chid=%d,lstatus=%x>: " + __FILE__ " line %d" + , lstatus, __LINE__ ); + child = child2 = 0; + status = -1; + + } + } + } + + close(fd[0]); + + /* if there is something running, wait for it to exit */ + + while (child || child2) { + int lstatus=0; + int chid; + + chid = wait(&lstatus); + + if (child && chid == child) { + + if (WIFEXITED(lstatus)) { /* exited ? */ + status = WEXITSTATUS(lstatus); + } else if (WIFSIGNALED(lstatus)) { /* killed ? */ + status = -1; + } else + continue; /* just stopped etc.. */ + child = 0; /* the child has exited */ + + } else if (child2 && chid == child2) { + + if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus)) + child2 = 0; + + } else { + + _pam_log(LOG_ALERT + ,"programming error <chid=%d,lstatus=%x>: " + __FILE__ " line %d" + , lstatus, __LINE__ ); + child = child2 = 0; + status = -1; + + } + } + + if (aterminal) { + /* reset to initial terminal mode */ + (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); + } + + if (ctrl & FILTER_DEBUG) { + _pam_log(LOG_DEBUG,"parent process exited"); /* clock off */ + } + + /* quit the parent process, returning the child's exit status */ + + exit(status); +} + +static int set_the_terminal(pam_handle_t *pamh) +{ + const char *tty; + + if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS + || tty == NULL) { + tty = ttyname(STDIN_FILENO); + if (tty == NULL) { + _pam_log(LOG_ERR, "couldn't get the tty name"); + return PAM_ABORT; + } + if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { + _pam_log(LOG_ERR, "couldn't set tty name"); + return PAM_ABORT; + } + } + return PAM_SUCCESS; +} + +static int need_a_filter(pam_handle_t *pamh + , int flags, int argc, const char **argv + , const char *name, int which_run) +{ + int ctrl; + char **evp; + const char *filterfile; + int retval; + + ctrl = process_args(pamh, argc, argv, name, &evp, &filterfile); + if (ctrl == -1) { + return PAM_AUTHINFO_UNAVAIL; + } + + /* set the tty to the old or the new one? */ + + if (!(ctrl & NON_TERM) && !(ctrl & NEW_TERM)) { + retval = set_the_terminal(pamh); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR, "tried and failed to set PAM_TTY"); + } + } else { + retval = PAM_SUCCESS; /* nothing to do which is always a success */ + } + + if (retval == PAM_SUCCESS && (ctrl & which_run)) { + retval = set_filter(pamh, flags, ctrl + , (const char **)evp, filterfile); + } + + if (retval == PAM_SUCCESS + && !(ctrl & NON_TERM) && (ctrl & NEW_TERM)) { + retval = set_the_terminal(pamh); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR + , "tried and failed to set new terminal as PAM_TTY"); + } + } + + free_evp(evp); + + if (ctrl & FILTER_DEBUG) { + _pam_log(LOG_DEBUG, "filter/%s, returning %d", name, retval); + _pam_log(LOG_DEBUG, "[%s]", pam_strerror(pamh, retval)); + } + + return retval; +} + +/* ----------------- public functions ---------------- */ + +/* + * here are the advertised access points ... + */ + +/* ------------------ authentication ----------------- */ + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh + , int flags, int argc, const char **argv) +{ + return need_a_filter(pamh, flags, argc, argv + , "authenticate", FILTER_RUN1); +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + return need_a_filter(pamh, flags, argc, argv, "setcred", FILTER_RUN2); +} + +/* --------------- account management ---------------- */ + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return need_a_filter(pamh, flags, argc, argv + , "setcred", FILTER_RUN1|FILTER_RUN2 ); +} + +/* --------------- session management ---------------- */ + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + return need_a_filter(pamh, flags, argc, argv + , "open_session", FILTER_RUN1); +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + return need_a_filter(pamh, flags, argc, argv + , "close_session", FILTER_RUN2); +} + +/* --------- updating authentication tokens --------- */ + + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + int runN; + + if (flags & PAM_PRELIM_CHECK) + runN = FILTER_RUN1; + else if (flags & PAM_UPDATE_AUTHTOK) + runN = FILTER_RUN2; + else { + _pam_log(LOG_ERR, "unknown flags for chauthtok (0x%X)", flags); + return PAM_TRY_AGAIN; + } + + return need_a_filter(pamh, flags, argc, argv, "chauthtok", runN); +} + +#ifdef PAM_STATIC + +/* ------------ stuff for static modules ------------ */ + +struct pam_module _pam_filter_modstruct = { + "pam_filter", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok, +}; + +#endif diff --git a/Linux-PAM/modules/pam_filter/upperLOWER/Makefile b/Linux-PAM/modules/pam_filter/upperLOWER/Makefile new file mode 100644 index 00000000..3e2d667f --- /dev/null +++ b/Linux-PAM/modules/pam_filter/upperLOWER/Makefile @@ -0,0 +1,39 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ +# +# This directory contains a pam_filter filter executable +# +# Created by Andrew Morgan <morgan@transmeta.com> 1996/3/11 +# + +include ../../../Make.Rules + +TITLE=upperLOWER + +# + +CFLAGS += -I../include + +OBJS = $(TITLE).o + +####################### don't edit below ####################### + +all: $(TITLE) + +$(TITLE): $(OBJS) + $(CC) $(CFLAGS) -o $(TITLE) $(OBJS) + $(STRIP) $(TITLE) + +install: + $(MKDIR) $(FAKEROOT)$(FILTERSDIR) + $(INSTALL) -m 511 $(TITLE) $(FAKEROOT)$(FILTERSDIR) + +remove: + cd $(FAKEROOT)$(FILTERSDIR) && rm -f $(TITLE) + +clean: + rm -f $(TITLE) $(OBJS) core *~ + +.c.o: + $(CC) $(CFLAGS) -c $< + diff --git a/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c b/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c new file mode 100644 index 00000000..59c0e0e3 --- /dev/null +++ b/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c @@ -0,0 +1,164 @@ +/* + * $Id: upperLOWER.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $ + * + * This is a sample filter program, for use with pam_filter (a module + * provided with Linux-PAM). This filter simply transposes upper and + * lower case letters, it is intended for demonstration purposes and + * it serves no purpose other than to annoy the user... + */ + +#include <security/_pam_aconf.h> + +#ifdef MEMORY_DEBUG +# undef exit +#endif /* MEMORY_DEBUG */ + +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <security/pam_filter.h> + +/* ---------------------------------------------------------------- */ + +#include <stdarg.h> +#ifdef hpux +# define log_this syslog +#else +static void log_this(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("upperLOWER", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} +#endif + +#include <ctype.h> + +static void do_transpose(char *buffer,int len) +{ + int i; + for (i=0; i<len; ++i) { + if (islower(buffer[i])) { + buffer[i] = toupper(buffer[i]); + } else { + buffer[i] = tolower(buffer[i]); + } + } +} + +extern char **environ; + +int main(int argc, char **argv) +{ + char buffer[BUFSIZ]; + fd_set readers; + void (*before_user)(char *,int); + void (*before_app)(char *,int); + +#ifdef DEBUG + { + int i; + + fprintf(stderr,"environment :[\r\n"); + for (i=0; environ[i]; ++i) { + fprintf(stderr,"-> %s\r\n",environ[i]); + } + fprintf(stderr,"]: end\r\n"); + } +#endif + + if (argc != 1) { +#ifdef DEBUG + fprintf(stderr,"filter invoked as conventional executable\n"); +#else + log_this(LOG_ERR, "filter invoked as conventional executable"); +#endif + exit(1); + } + + before_user = before_app = do_transpose; /* assign filter functions */ + + /* enter a loop that deals with the input and output of the + user.. passing it to and from the application */ + + FD_ZERO(&readers); /* initialize reading mask */ + + for (;;) { + + FD_SET(APPOUT_FILENO, &readers); /* wake for output */ + FD_SET(APPERR_FILENO, &readers); /* wake for error */ + FD_SET(STDIN_FILENO, &readers); /* wake for input */ + + if ( select(APPTOP_FILE,&readers,NULL,NULL,NULL) < 0 ) { +#ifdef DEBUG + fprintf(stderr,"select failed\n"); +#else + log_this(LOG_WARNING,"select failed"); +#endif + break; + } + + /* application errors */ + + if ( FD_ISSET(APPERR_FILENO,&readers) ) { + int got = read(APPERR_FILENO, buffer, BUFSIZ); + if (got <= 0) { + break; + } else { + /* translate to give to real terminal */ + if (before_user != NULL) + before_user(buffer, got); + if ( write(STDERR_FILENO, buffer, got) != got ) { + log_this(LOG_WARNING,"couldn't write %d bytes?!",got); + break; + } + } + } else if ( FD_ISSET(APPOUT_FILENO,&readers) ) { /* app output */ + int got = read(APPOUT_FILENO, buffer, BUFSIZ); + if (got <= 0) { + break; + } else { + /* translate to give to real terminal */ + if (before_user != NULL) + before_user(buffer, got); + if ( write(STDOUT_FILENO, buffer, got) != got ) { + log_this(LOG_WARNING,"couldn't write %d bytes!?",got); + break; + } + } + } + + if ( FD_ISSET(STDIN_FILENO, &readers) ) { /* user input */ + int got = read(STDIN_FILENO, buffer, BUFSIZ); + if (got < 0) { + log_this(LOG_WARNING,"user input junked"); + break; + } else if (got) { + /* translate to give to application */ + if (before_app != NULL) + before_app(buffer, got); + if ( write(APPIN_FILENO, buffer, got) != got ) { + log_this(LOG_WARNING,"couldn't pass %d bytes!?",got); + break; + } + } else { + /* nothing received -- an error? */ + log_this(LOG_WARNING,"user input null?"); + break; + } + } + } + + exit(0); +} + + + diff --git a/Linux-PAM/modules/pam_ftp/Makefile b/Linux-PAM/modules/pam_ftp/Makefile new file mode 100644 index 00000000..a1088e17 --- /dev/null +++ b/Linux-PAM/modules/pam_ftp/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_ftp + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_ftp/README b/Linux-PAM/modules/pam_ftp/README new file mode 100644 index 00000000..6d03330c --- /dev/null +++ b/Linux-PAM/modules/pam_ftp/README @@ -0,0 +1,18 @@ +This is the README for pam_ftp +------------------------------ + +This module is an authentication module that does simple ftp +authentication. + +Recognized arguments: + + "debug" print debug messages + "users=" comma separated list of users which + could login only with email adress + "ignore" allow invalid email adresses + +Options for: +auth: for authentication it provides pam_authenticate() and + pam_setcred() hooks. + +Thorsten Kukuk <kukuk@suse.de>, 17. June 1999 diff --git a/Linux-PAM/modules/pam_ftp/pam_ftp.c b/Linux-PAM/modules/pam_ftp/pam_ftp.c new file mode 100644 index 00000000..1512a65d --- /dev/null +++ b/Linux-PAM/modules/pam_ftp/pam_ftp.c @@ -0,0 +1,297 @@ +/* pam_ftp module */ + +/* + * $Id: pam_ftp.c,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 + * + */ + +#define PLEASE_ENTER_PASSWORD "Password required for %s." +#define GUEST_LOGIN_PROMPT "Guest login ok, " \ +"send your complete e-mail address as password." + +/* the following is a password that "can't be correct" */ +#define BLOCK_PASSWORD "\177BAD PASSWPRD\177" + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <string.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static int converse(pam_handle_t *pamh, int nargs + , struct pam_message **message + , struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse\n")); + + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS ) { + + retval = conv->conv(nargs, ( const struct pam_message ** ) message + , response, conv->appdata_ptr); + + D(("returned from application's conversation function\n")); + + if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) { + _pam_log(LOG_DEBUG, "conversation failure [%s]" + , pam_strerror(pamh, retval)); + } + + } else { + _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]" + , pam_strerror(pamh, retval)); + } + + D(("ready to return from module conversation\n")); + + return retval; /* propagate error status */ +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 01 +#define PAM_IGNORE_EMAIL 02 +#define PAM_NO_ANON 04 + +static int _pam_parse(int argc, const char **argv, char **users) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strncmp(*argv,"users=",6)) { + *users = x_strdup(6+*argv); + if (*users == NULL) { + ctrl |= PAM_NO_ANON; + _pam_log(LOG_CRIT, "failed to duplicate user list - anon off"); + } + } else if (!strcmp(*argv,"ignore")) { + ctrl |= PAM_IGNORE_EMAIL; + } else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + +/* + * check if name is in list or default list. place users name in *_user + * return 1 if listed 0 if not. + */ + +static int lookup(const char *name, char *list, const char **_user) +{ + int anon = 0; + + *_user = name; /* this is the default */ + if (list) { + const char *l; + char *x; + + x = list; + while ((l = strtok(x, ","))) { + x = NULL; + if (!strcmp(name, l)) { + *_user = list; + anon = 1; + } + } + } else { +#define MAX_L 2 + static const char *l[MAX_L] = { "ftp", "anonymous" }; + int i; + + for (i=0; i<MAX_L; ++i) { + if (!strcmp(l[i], name)) { + *_user = l[0]; + anon = 1; + break; + } + } + } + + return anon; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int retval, anon=0, ctrl; + const char *user; + char *users=NULL; + + /* + * this module checks if the user name is ftp or annonymous. If + * this is the case, it can set the PAM_RUSER to the entered email + * address and SUCCEEDS, otherwise it FAILS. + */ + + ctrl = _pam_parse(argc, argv, &users); + + retval = pam_get_user(pamh, &user, NULL); + if (retval != PAM_SUCCESS || user == NULL) { + _pam_log(LOG_ERR, "no user specified"); + return PAM_USER_UNKNOWN; + } + + if (!(ctrl & PAM_NO_ANON)) { + anon = lookup(user, users, &user); + } + + if (anon) { + retval = pam_set_item(pamh, PAM_USER, (const void *)user); + if (retval != PAM_SUCCESS || user == NULL) { + _pam_log(LOG_ERR, "user resetting failed"); + return PAM_USER_UNKNOWN; + } + } + + /* + * OK. we require an email address for user or the user's password. + * - build conversation and get their input. + */ + + { + struct pam_message msg[1], *mesg[1]; + struct pam_response *resp=NULL; + const char *token; + char *prompt=NULL; + int i=0; + + if (!anon) { + prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user)); + if (prompt == NULL) { + D(("out of memory!?")); + return PAM_BUF_ERR; + } else { + sprintf(prompt, PLEASE_ENTER_PASSWORD, user); + msg[i].msg = prompt; + } + } else { + msg[i].msg = GUEST_LOGIN_PROMPT; + } + + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + mesg[i] = &msg[i]; + + retval = converse(pamh, ++i, mesg, &resp); + if (prompt) { + _pam_overwrite(prompt); + _pam_drop(prompt); + } + + if (retval != PAM_SUCCESS) { + if (resp != NULL) + _pam_drop_reply(resp,i); + return ((retval == PAM_CONV_AGAIN) + ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL); + } + + if (anon) { + /* XXX: Some effort should be made to verify this email address! */ + + if (!(ctrl & PAM_IGNORE_EMAIL)) { + token = strtok(resp->resp, "@"); + retval = pam_set_item(pamh, PAM_RUSER, token); + + if ((token) && (retval == PAM_SUCCESS)) { + token = strtok(NULL, "@"); + retval = pam_set_item(pamh, PAM_RHOST, token); + } + } + + /* we are happy to grant annonymous access to the user */ + retval = PAM_SUCCESS; + + } else { + /* + * we have a password so set AUTHTOK + */ + + (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp); + + /* + * this module failed, but the next one might succeed with + * this password. + */ + + retval = PAM_AUTH_ERR; + } + + if (resp) { /* clean up */ + _pam_drop_reply(resp, i); + } + + /* success or failure */ + + return retval; + } +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_IGNORE; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_ftp_modstruct = { + "pam_ftp", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_group/Makefile b/Linux-PAM/modules/pam_group/Makefile new file mode 100644 index 00000000..11593e25 --- /dev/null +++ b/Linux-PAM/modules/pam_group/Makefile @@ -0,0 +1,21 @@ +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_group +LOCAL_CONFILE=./group.conf +INSTALLED_CONFILE=$(SCONFIGD)/group.conf + +DEFS=-DDEFAULT_CONF_FILE=\"$(CONFILE)\" +CFLAGS += $(DEFS) + +MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" +MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) +MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_group/group.conf b/Linux-PAM/modules/pam_group/group.conf new file mode 100644 index 00000000..e721b990 --- /dev/null +++ b/Linux-PAM/modules/pam_group/group.conf @@ -0,0 +1,60 @@ +## +## Note, to get this to work as it is currently typed you need +## +## 1. to run an application as root +## 2. add the following groups to the /etc/group file: +## floppy, games, sound +## +# +# *** Please note that giving group membership on a session basis is +# *** NOT inherently secure. If a user can create an executable that +# *** is setgid a group that they are infrequently given membership +# *** of, they can basically obtain group membership any time they +# *** like. Example: games are allowed between the hours of 6pm and 6am +# *** user joe logs in at 7pm writes a small C-program toplay.c that +# *** invokes their favorite shell, compiles it and does +# *** "chgrp games toplay; chmod g+s toplay". They are basically able +# *** to play games any time... You have been warned. AGM +# +# this is an example configuration file for the pam_group module. Its +# syntax is based on that of the pam_time module and (at some point in +# the distant past was inspired by the 'shadow' package) +# +# the syntax of the lines is as follows: +# +# services;ttys;users;times;groups +# +# white space is ignored and lines maybe extended with '\\n' (escaped +# newlines). From reading these comments, it is clear that +# text following a '#' is ignored to the end of the line. +# +# the first four fields are described in the pam_time directory. +# The only difference for these is how the time field is interpretted: +# it is used to indicate "when" these groups are to be given to the user. +# +# groups +# The (comma or space separated) list of groups that the user +# inherits membership of. These groups are added if the previous +# fields are satisfied by the user's request +# + +# +# Here is a simple example: running 'xsh' on tty* (any ttyXXX device), +# the user 'us' is given access to the floppy (through membership of +# the floppy group) +# + +#xsh;tty*&!ttyp*;us;Al0000-2400;floppy + +# +# another example: running 'xsh' on tty* (any ttyXXX device), +# the user 'sword' is given access to games (through membership of +# the floppy group) after work hours +# + +#xsh; tty* ;sword;!Wk0900-1800;games, sound +#xsh; tty* ;*;Al0900-1800;floppy + +# +# End of group.conf file +# diff --git a/Linux-PAM/modules/pam_group/pam_group.c b/Linux-PAM/modules/pam_group/pam_group.c new file mode 100644 index 00000000..b6b6ee08 --- /dev/null +++ b/Linux-PAM/modules/pam_group/pam_group.c @@ -0,0 +1,856 @@ +/* pam_group module */ + +/* + * $Id: pam_group.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/7/6 + */ + +const static char rcsid[] = +"$Id: pam_group.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $;\n" +"Version 0.5 for Linux-PAM\n" +"Copyright (c) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; + +#define _BSD_SOURCE + +#include <sys/file.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <stdarg.h> +#include <time.h> +#include <syslog.h> +#include <string.h> + +#include <grp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifdef DEFAULT_CONF_FILE +# define PAM_GROUP_CONF DEFAULT_CONF_FILE /* from external define */ +#else +# define PAM_GROUP_CONF "/etc/security/group.conf" +#endif +#define PAM_GROUP_BUFLEN 1000 +#define FIELD_SEPARATOR ';' /* this is new as of .02 */ + +#ifdef TRUE +# undef TRUE +#endif +#ifdef FALSE +# undef FALSE +#endif + +typedef enum { FALSE, TRUE } boolean; +typedef enum { AND, OR } operator; + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* --- static functions for checking whether the user should be let in --- */ + +static void _log_err(const char *format, ... ) +{ + va_list args; + + va_start(args, format); + openlog("pam_group", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(LOG_CRIT, format, args); + va_end(args); + closelog(); +} + +static void shift_bytes(char *mem, int from, int by) +{ + while (by-- > 0) { + *mem = mem[from]; + ++mem; + } +} + +static int read_field(int fd, char **buf, int *from, int *to) +{ + /* is buf set ? */ + + if (! *buf) { + *buf = (char *) malloc(PAM_GROUP_BUFLEN); + if (! *buf) { + _log_err("out of memory"); + return -1; + } + *from = *to = 0; + fd = open(PAM_GROUP_CONF, O_RDONLY); + } + + /* do we have a file open ? return error */ + + if (fd < 0 && *to <= 0) { + _log_err( PAM_GROUP_CONF " not opened"); + memset(*buf, 0, PAM_GROUP_BUFLEN); + _pam_drop(*buf); + return -1; + } + + /* check if there was a newline last time */ + + if ((*to > *from) && (*to > 0) + && ((*buf)[*from] == '\0')) { /* previous line ended */ + (*from)++; + (*buf)[0] = '\0'; + return fd; + } + + /* ready for more data: first shift the buffer's remaining data */ + + *to -= *from; + shift_bytes(*buf, *from, *to); + *from = 0; + (*buf)[*to] = '\0'; + + while (fd >= 0 && *to < PAM_GROUP_BUFLEN) { + int i; + + /* now try to fill the remainder of the buffer */ + + i = read(fd, *to + *buf, PAM_GROUP_BUFLEN - *to); + if (i < 0) { + _log_err("error reading " PAM_GROUP_CONF); + return -1; + } else if (!i) { + close(fd); + fd = -1; /* end of file reached */ + } else + *to += i; + + /* + * contract the buffer. Delete any comments, and replace all + * multiple spaces with single commas + */ + + i = 0; +#ifdef DEBUG_DUMP + D(("buffer=<%s>",*buf)); +#endif + while (i < *to) { + if ((*buf)[i] == ',') { + int j; + + for (j=++i; j<*to && (*buf)[j] == ','; ++j); + if (j!=i) { + shift_bytes(i + (*buf), j-i, (*to) - j); + *to -= j-i; + } + } + switch ((*buf)[i]) { + int j,c; + case '#': + for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); + if (j >= *to) { + (*buf)[*to = ++i] = '\0'; + } else if (c == '\n') { + shift_bytes(i + (*buf), j-i, (*to) - j); + *to -= j-i; + ++i; + } else { + _log_err("internal error in " __FILE__ + " at line %d", __LINE__ ); + return -1; + } + break; + case '\\': + if ((*buf)[i+1] == '\n') { + shift_bytes(i + *buf, 2, *to - (i+2)); + *to -= 2; + } else { + ++i; /* we don't escape non-newline characters */ + } + break; + case '!': + case ' ': + case '\t': + if ((*buf)[i] != '!') + (*buf)[i] = ','; + /* delete any trailing spaces */ + for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' + || c == '\t' ); ++j); + shift_bytes(i + *buf, j-i, (*to)-j ); + *to -= j-i; + break; + default: + ++i; + } + } + } + + (*buf)[*to] = '\0'; + + /* now return the next field (set the from/to markers) */ + { + int i; + + for (i=0; i<*to; ++i) { + switch ((*buf)[i]) { + case '#': + case '\n': /* end of the line/file */ + (*buf)[i] = '\0'; + *from = i; + return fd; + case FIELD_SEPARATOR: /* end of the field */ + (*buf)[i] = '\0'; + *from = ++i; + return fd; + } + } + *from = i; + (*buf)[*from] = '\0'; + } + + if (*to <= 0) { + D(("[end of text]")); + *buf = NULL; + } + return fd; +} + +/* read a member from a field */ + +static int logic_member(const char *string, int *at) +{ + int len,c,to; + int done=0; + int token=0; + + len=0; + to=*at; + do { + c = string[to++]; + + switch (c) { + + case '\0': + --to; + done = 1; + break; + + case '&': + case '|': + case '!': + if (token) { + --to; + } + done = 1; + break; + + default: + if (isalpha(c) || c == '*' || isdigit(c) || c == '_' + || c == '-' || c == '.' || c == '/') { + token = 1; + } else if (token) { + --to; + done = 1; + } else { + ++*at; + } + } + } while (!done); + + return to - *at; +} + +typedef enum { VAL, OP } expect; + +static boolean logic_field(const void *me, const char *x, int rule, + boolean (*agrees)(const void *, const char * + , int, int)) +{ + boolean left=FALSE, right, not=FALSE; + operator oper=OR; + int at=0, l; + expect next=VAL; + + while ((l = logic_member(x,&at))) { + int c = x[at]; + + if (next == VAL) { + if (c == '!') + not = !not; + else if (isalpha(c) || c == '*') { + right = not ^ agrees(me, x+at, l, rule); + if (oper == AND) + left &= right; + else + left |= right; + next = OP; + } else { + _log_err("garbled syntax; expected name (rule #%d)", rule); + return FALSE; + } + } else { /* OP */ + switch (c) { + case '&': + oper = AND; + break; + case '|': + oper = OR; + break; + default: + _log_err("garbled syntax; expected & or | (rule #%d)" + , rule); + D(("%c at %d",c,at)); + return FALSE; + } + next = VAL; + } + at += l; + } + + return left; +} + +static boolean is_same(const void *A, const char *b, int len, int rule) +{ + int i; + const char *a; + + a = A; + for (i=0; len > 0; ++i, --len) { + if (b[i] != a[i]) { + if (b[i++] == '*') { + return (!--len || !strncmp(b+i,a+strlen(a)-len,len)); + } else + return FALSE; + } + } + return ( !len ); +} + +typedef struct { + int day; /* array of 7 bits, one set for today */ + int minute; /* integer, hour*100+minute for now */ +} TIME; + +struct day { + const char *d; + int bit; +} static const days[11] = { + { "su", 01 }, + { "mo", 02 }, + { "tu", 04 }, + { "we", 010 }, + { "th", 020 }, + { "fr", 040 }, + { "sa", 0100 }, + { "wk", 076 }, + { "wd", 0101 }, + { "al", 0177 }, + { NULL, 0 } +}; + +static TIME time_now(void) +{ + struct tm *local; + time_t the_time; + TIME this; + + the_time = time((time_t *)0); /* get the current time */ + local = localtime(&the_time); + this.day = days[local->tm_wday].bit; + this.minute = local->tm_hour*100 + local->tm_min; + + D(("day: 0%o, time: %.4d", this.day, this.minute)); + return this; +} + +/* take the current date and see if the range "date" passes it */ +static boolean check_time(const void *AT, const char *times, int len, int rule) +{ + boolean not,pass; + int marked_day, time_start, time_end; + const TIME *at; + int i,j=0; + + at = AT; + D(("checking: 0%o/%.4d vs. %s", at->day, at->minute, times)); + + if (times == NULL) { + /* this should not happen */ + _log_err("internal error: " __FILE__ " line %d", __LINE__); + return FALSE; + } + + if (times[j] == '!') { + ++j; + not = TRUE; + } else { + not = FALSE; + } + + for (marked_day = 0; len > 0 && isalpha(times[j]); --len) { + int this_day=-1; + + D(("%c%c ?", times[j], times[j+1])); + for (i=0; days[i].d != NULL; ++i) { + if (tolower(times[j]) == days[i].d[0] + && tolower(times[j+1]) == days[i].d[1] ) { + this_day = days[i].bit; + break; + } + } + j += 2; + if (this_day == -1) { + _log_err("bad day specified (rule #%d)", rule); + return FALSE; + } + marked_day ^= this_day; + } + if (marked_day == 0) { + _log_err("no day specified"); + return FALSE; + } + D(("day range = 0%o", marked_day)); + + time_start = 0; + for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) { + time_start *= 10; + time_start += times[i+j]-'0'; /* is this portable? */ + } + j += i; + + if (times[j] == '-') { + time_end = 0; + for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) { + time_end *= 10; + time_end += times[i+j]-'0'; /* is this portable? */ + } + j += i; + } else + time_end = -1; + + D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j])); + if (i != 5 || time_end == -1) { + _log_err("no/bad times specified (rule #%d)", rule); + return TRUE; + } + D(("times(%d to %d)", time_start,time_end)); + D(("marked_day = 0%o", marked_day)); + + /* compare with the actual time now */ + + pass = FALSE; + if (time_start < time_end) { /* start < end ? --> same day */ + if ((at->day & marked_day) && (at->minute >= time_start) + && (at->minute < time_end)) { + D(("time is listed")); + pass = TRUE; + } + } else { /* spans two days */ + if ((at->day & marked_day) && (at->minute >= time_start)) { + D(("caught on first day")); + pass = TRUE; + } else { + marked_day <<= 1; + marked_day |= (marked_day & 0200) ? 1:0; + D(("next day = 0%o", marked_day)); + if ((at->day & marked_day) && (at->minute <= time_end)) { + D(("caught on second day")); + pass = TRUE; + } + } + } + + return (not ^ pass); +} + +static int find_member(const char *string, int *at) +{ + int len,c,to; + int done=0; + int token=0; + + len=0; + to=*at; + do { + c = string[to++]; + + switch (c) { + + case '\0': + --to; + done = 1; + break; + + case '&': + case '|': + case '!': + if (token) { + --to; + } + done = 1; + break; + + default: + if (isalpha(c) || isdigit(c) || c == '_' || c == '*' + || c == '-') { + token = 1; + } else if (token) { + --to; + done = 1; + } else { + ++*at; + } + } + } while (!done); + + return to - *at; +} + +#define GROUP_BLK 10 +#define blk_size(len) (((len-1 + GROUP_BLK)/GROUP_BLK)*GROUP_BLK) + +static int mkgrplist(char *buf, gid_t **list, int len) +{ + int l,at=0; + int blks; + + blks = blk_size(len); + D(("cf. blks=%d and len=%d", blks,len)); + + while ((l = find_member(buf,&at))) { + int edge; + + if (len >= blks) { + gid_t *tmp; + + D(("allocating new block")); + tmp = (gid_t *) realloc((*list) + , sizeof(gid_t) * (blks += GROUP_BLK)); + if (tmp != NULL) { + (*list) = tmp; + } else { + _log_err("out of memory for group list"); + free(*list); + (*list) = NULL; + return -1; + } + } + + /* '\0' terminate the entry */ + + edge = (buf[at+l]) ? 1:0; + buf[at+l] = '\0'; + D(("found group: %s",buf+at)); + + /* this is where we convert a group name to a gid_t */ +#ifdef WANT_PWDB + { + int retval; + const struct pwdb *pw=NULL; + + retval = pwdb_locate("group", PWDB_DEFAULT, buf+at + , PWDB_ID_UNKNOWN, &pw); + if (retval != PWDB_SUCCESS) { + _log_err("bad group: %s; %s", buf+at, pwdb_strerror(retval)); + } else { + const struct pwdb_entry *pwe=NULL; + + D(("group %s exists", buf+at)); + retval = pwdb_get_entry(pw, "gid", &pwe); + if (retval == PWDB_SUCCESS) { + D(("gid = %d [%p]",* (const gid_t *) pwe->value,list)); + (*list)[len++] = * (const gid_t *) pwe->value; + pwdb_entry_delete(&pwe); /* tidy up */ + } else { + _log_err("%s group entry is bad; %s" + , pwdb_strerror(retval)); + } + pw = NULL; /* break link - cached for later use */ + } + } +#else + { + const struct group *grp; + + grp = getgrnam(buf+at); + if (grp == NULL) { + _log_err("bad group: %s", buf+at); + } else { + D(("group %s exists", buf+at)); + (*list)[len++] = grp->gr_gid; + } + } +#endif + + /* next entry along */ + + at += l + edge; + } + D(("returning with [%p/len=%d]->%p",list,len,*list)); + return len; +} + + +static int check_account(const char *service, const char *tty + , const char *user) +{ + int from=0,to=0,fd=-1; + char *buffer=NULL; + int count=0; + TIME here_and_now; + int retval=PAM_SUCCESS; + gid_t *grps; + int no_grps; + + /* + * first we get the current list of groups - the application + * will have previously done an initgroups(), or equivalent. + */ + + D(("counting supplementary groups")); + no_grps = getgroups(0, NULL); /* find the current number of groups */ + if (no_grps > 0) { + grps = calloc( blk_size(no_grps) , sizeof(gid_t) ); + D(("copying current list into grps [%d big]",blk_size(no_grps))); + (void) getgroups(no_grps, grps); +#ifdef DEBUG + { + int z; + for (z=0; z<no_grps; ++z) { + D(("gid[%d]=%d", z, grps[z])); + } + } +#endif + } else { + D(("no supplementary groups known")); + no_grps = 0; + grps = NULL; + } + + here_and_now = time_now(); /* find current time */ + + /* parse the rules in the configuration file */ + do { + int good=TRUE; + + /* here we get the service name field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + /* empty line .. ? */ + continue; + } + ++count; + D(("working on rule #%d",count)); + + good = logic_field(service, buffer, count, is_same); + D(("with service: %s", good ? "passes":"fails" )); + + /* here we get the terminal name field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_GROUP_CONF "; no tty entry #%d", count); + continue; + } + good &= logic_field(tty, buffer, count, is_same); + D(("with tty: %s", good ? "passes":"fails" )); + + /* here we get the username field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_GROUP_CONF "; no user entry #%d", count); + continue; + } + good &= logic_field(user, buffer, count, is_same); + D(("with user: %s", good ? "passes":"fails" )); + + /* here we get the time field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_GROUP_CONF "; no time entry #%d", count); + continue; + } + + good &= logic_field(&here_and_now, buffer, count, check_time); + D(("with time: %s", good ? "passes":"fails" )); + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_GROUP_CONF "; no listed groups for rule #%d" + , count); + continue; + } + + /* + * so we have a list of groups, we need to turn it into + * something to send to setgroups(2) + */ + + if (good) { + D(("adding %s to gid list", buffer)); + good = mkgrplist(buffer, &grps, no_grps); + if (good < 0) { + no_grps = 0; + } else { + no_grps = good; + } + } + + /* check the line is terminated correctly */ + + fd = read_field(fd,&buffer,&from,&to); + if (buffer && buffer[0]) { + _log_err(PAM_GROUP_CONF "; poorly terminated rule #%d", count); + } + + if (good > 0) { + D(("rule #%d passed, added %d groups", count, good)); + } else if (good < 0) { + retval = PAM_BUF_ERR; + } else { + D(("rule #%d failed", count)); + } + + } while (buffer); + + /* now set the groups for the user */ + + if (no_grps > 0) { + int err; + D(("trying to set %d groups", no_grps)); +#ifdef DEBUG + for (err=0; err<no_grps; ++err) { + D(("gid[%d]=%d", err, grps[err])); + } +#endif + if ((err = setgroups(no_grps, grps))) { + D(("but couldn't set groups %d", err)); + _log_err("unable to set the group membership for user (err=%d)" + , err); + retval = PAM_CRED_ERR; + } + } + + if (grps) { /* tidy up */ + memset(grps, 0, sizeof(gid_t) * blk_size(no_grps)); + _pam_drop(grps); + no_grps = 0; + } + + return retval; +} + +/* --- public authentication management functions --- */ + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + return PAM_IGNORE; +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + const char *service=NULL, *tty=NULL; + const char *user=NULL; + int retval; + unsigned setting; + + /* only interested in establishing credentials */ + + setting = flags; + if (!(setting & PAM_ESTABLISH_CRED)) { + D(("ignoring call - not for establishing credentials")); + return PAM_SUCCESS; /* don't fail because of this */ + } + + /* set service name */ + + if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) + != PAM_SUCCESS || service == NULL) { + _log_err("cannot find the current service name"); + return PAM_ABORT; + } + + /* set username */ + + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL + || *user == '\0') { + _log_err("cannot determine the user's name"); + return PAM_USER_UNKNOWN; + } + + /* set tty name */ + + if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS + || tty == NULL) { + D(("PAM_TTY not set, probing stdin")); + tty = ttyname(STDIN_FILENO); + if (tty == NULL) { + _log_err("couldn't get the tty name"); + return PAM_ABORT; + } + if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { + _log_err("couldn't set tty name"); + return PAM_ABORT; + } + } + + if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */ + tty += 5; + } + + /* good, now we have the service name, the user and the terminal name */ + + D(("service=%s", service)); + D(("user=%s", user)); + D(("tty=%s", tty)); + +#ifdef WANT_PWDB + + /* We initialize the pwdb library and check the account */ + retval = pwdb_start(); /* initialize */ + if (retval == PWDB_SUCCESS) { + retval = check_account(service,tty,user); /* get groups */ + (void) pwdb_end(); /* tidy up */ + } else { + D(("failed to initialize pwdb; %s", pwdb_strerror(retval))); + _log_err("unable to initialize libpwdb"); + retval = PAM_ABORT; + } + +#else /* WANT_PWDB */ + retval = check_account(service,tty,user); /* get groups */ +#endif /* WANT_PWDB */ + + return retval; +} + +/* end of module definition */ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_group_modstruct = { + "pam_group", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL +}; +#endif diff --git a/Linux-PAM/modules/pam_issue/Makefile b/Linux-PAM/modules/pam_issue/Makefile new file mode 100644 index 00000000..1bc611af --- /dev/null +++ b/Linux-PAM/modules/pam_issue/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_issue + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_issue/pam_issue.c b/Linux-PAM/modules/pam_issue/pam_issue.c new file mode 100644 index 00000000..1f4853de --- /dev/null +++ b/Linux-PAM/modules/pam_issue/pam_issue.c @@ -0,0 +1,308 @@ +/* pam_issue module - a simple /etc/issue parser to set PAM_USER_PROMPT + * + * Copyright 1999 by Ben Collins <bcollins@debian.org> + * + * Needs to be called before any other auth modules so we can setup the + * user prompt before it's first used. Allows one argument option, which + * is the full path to a file to be used for issue (uses /etc/issue as a + * default) such as "issue=/etc/issue.telnet". + * + * We can also parse escapes within the the issue file (enabled by + * default, but can be disabled with the "noesc" option). It's the exact + * same parsing as util-linux's agetty program performs. + * + * Released under the GNU LGPL version 2 or later + */ + +#define _GNU_SOURCE +#define _BSD_SOURCE + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/utsname.h> +#include <utmp.h> +#include <malloc.h> +#include <time.h> + +#include <security/_pam_macros.h> + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +static int _user_prompt_set = 0; + +char *do_prompt (FILE *); + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int retval = PAM_SUCCESS; + FILE *fd; + int parse_esc = 1; + char *prompt_tmp = NULL; + const char *cur_prompt = NULL; + struct stat st; + char *issue_file = NULL; + + /* If we've already set the prompt, don't set it again */ + if(_user_prompt_set) + return PAM_IGNORE; + else + /* we set this here so if we fail below, we wont get further + than this next time around (only one real failure) */ + _user_prompt_set = 1; + + for ( ; argc-- > 0 ; ++argv ) { + if (!strncmp(*argv,"issue=",6)) { + issue_file = (char *) strdup(6+*argv); + if (issue_file != NULL) { + D(("set issue_file to: %s", issue_file)); + } else { + D(("failed to strdup issue_file - ignored")); + return PAM_IGNORE; + } + } else if (!strcmp(*argv,"noesc")) { + parse_esc = 0; + D(("turning off escape parsing by request")); + } else + D(("unknown option passed: %s", *argv)); + } + + if (issue_file == NULL) + issue_file = strdup("/etc/issue"); + + if ((fd = fopen(issue_file, "r")) != NULL) { + int tot_size = 0; + + if (fstat(fileno(fd), &st) < 0) + return PAM_IGNORE; + + retval = pam_get_item(pamh, PAM_USER_PROMPT, + (const void **) &cur_prompt); + if (retval != PAM_SUCCESS) { + return PAM_IGNORE; + } + if (cur_prompt == NULL) { + cur_prompt = ""; + } + + /* first read in the issue file */ + + if (parse_esc) { + prompt_tmp = do_prompt(fd); + if (prompt_tmp == NULL) { + return PAM_IGNORE; + } + } else { + int count = 0; + + prompt_tmp = malloc(st.st_size + 1); + if (prompt_tmp == NULL) { + return PAM_IGNORE; + } + memset (prompt_tmp, '\0', st.st_size + 1); + count = fread(prompt_tmp, sizeof(char *), st.st_size, fd); + if (count != st.st_size) { + free(prompt_tmp); + return PAM_IGNORE; + } + prompt_tmp[st.st_size] = '\0'; + } + + fclose(fd); + + tot_size = strlen(prompt_tmp) + strlen(cur_prompt) + 1; + + /* + * alloc some extra space for the original prompt + * and postpend it to the buffer + */ + { + char *prompt_tmp_tmp = prompt_tmp; + + prompt_tmp = realloc(prompt_tmp, tot_size); + if (prompt_tmp == NULL) { + prompt_tmp = prompt_tmp_tmp; + retval = PAM_IGNORE; + goto cleanup; + } + } + + strcpy(prompt_tmp+strlen(prompt_tmp), cur_prompt); + + prompt_tmp[tot_size] = '\0'; + + retval = pam_set_item(pamh, PAM_USER_PROMPT, + (const char *) prompt_tmp); + + cleanup: + free(issue_file); + free(prompt_tmp); + + } else { + D(("could not open issue_file: %s", issue_file)); + return PAM_IGNORE; + } + + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return PAM_IGNORE; +} + +char *do_prompt(FILE *fd) +{ + int c, size = 1024; + char *issue = (char *)malloc(size); + char buf[1024]; + struct utsname uts; + + if (issue == NULL || fd == NULL) + return NULL; + + issue[0] = '\0'; /* zero this, for strcat to work on first buf */ + (void) uname(&uts); + + while ((c = getc(fd)) != EOF) { + if (c == '\\') { + c = getc(fd); + switch (c) { + case 's': + snprintf (buf, 1024, "%s", uts.sysname); + break; + case 'n': + snprintf (buf, 1024, "%s", uts.nodename); + break; + case 'r': + snprintf (buf, 1024, "%s", uts.release); + break; + case 'v': + snprintf (buf, 1024, "%s", uts.version); + break; + case 'm': + snprintf (buf, 1024, "%s", uts.machine); + break; + case 'o': + { + char domainname[256]; + + getdomainname(domainname, sizeof(domainname)); + domainname[sizeof(domainname)-1] = '\0'; + snprintf (buf, 1024, "%s", domainname); + } + break; + + case 'd': + case 't': + { + const char *weekday[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", + "Fri", "Sat" }; + const char *month[] = { + "Jan", "Feb", "Mar", "Apr", "May", + "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" }; + time_t now; + struct tm *tm; + + (void) time (&now); + tm = localtime(&now); + + if (c == 'd') + snprintf (buf, 1024, "%s %s %d %d", + weekday[tm->tm_wday], month[tm->tm_mon], + tm->tm_mday, + tm->tm_year + 1900); + else + snprintf (buf, 1024, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + } + break; + case 'l': + { + char *ttyn = ttyname(1); + if (!strncmp(ttyn, "/dev/", 5)) + ttyn += 5; + snprintf (buf, 1024, "%s", ttyn); + } + break; + case 'u': + case 'U': + { + int users = 0; + struct utmp *ut; + setutent(); + while ((ut = getutent())) + if (ut->ut_type == USER_PROCESS) + users++; + endutent(); + printf ("%d ", users); + if (c == 'U') + snprintf (buf, 1024, "%s", (users == 1) ? + " user" : " users"); + break; + } + default: + buf[0] = c; buf[1] = '\0'; + } + if ((strlen(issue) + strlen(buf)) < size + 1) { + char *old_issue = issue; + + size += strlen(buf) + 1; + issue = (char *) realloc (issue, size); + if (issue == NULL) { + free(old_issue); + return NULL; + } + } + strcat(issue, buf); + } else { + buf[0] = c; buf[1] = '\0'; + if ((strlen(issue) + strlen(buf)) < size + 1) { + char *old_issue = issue; + + size += strlen(buf) + 1; + issue = (char *) realloc (issue, size); + if (issue == NULL) { + free(old_issue); + return NULL; + } + } + strcat(issue, buf); + } + } + + return issue; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_issue_modstruct = { + "pam_issue", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_lastlog/Makefile b/Linux-PAM/modules/pam_lastlog/Makefile new file mode 100644 index 00000000..18042b47 --- /dev/null +++ b/Linux-PAM/modules/pam_lastlog/Makefile @@ -0,0 +1,19 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +ifeq ($(HAVE_LIBUTIL),yes) + MODULE_SIMPLE_EXTRALIBS += -lutil +endif + +TITLE=pam_lastlog + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_lastlog/pam_lastlog.c b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c new file mode 100644 index 00000000..89cea3d6 --- /dev/null +++ b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c @@ -0,0 +1,462 @@ +/* pam_lastlog module */ + +/* + * $Id: pam_lastlog.c,v 1.1.1.2 2002/09/15 20:08:49 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 + * + * This module does the necessary work to display the last login + * time+date for this user, it then updates this entry for the + * present (login) service. + */ + +#include <security/_pam_aconf.h> + +#include <fcntl.h> +#include <time.h> +#ifdef HAVE_UTMP_H +# include <utmp.h> +#else +# include <lastlog.h> +#endif +#include <pwd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <syslog.h> +#include <unistd.h> + +#ifdef WANT_PWDB +#include <pwdb/pwdb_public.h> /* use POSIX front end */ +#endif + +#if defined(hpux) || defined(sunos) || defined(solaris) +# ifndef _PATH_LASTLOG +# define _PATH_LASTLOG "/usr/adm/lastlog" +# endif /* _PATH_LASTLOG */ +# ifndef UT_HOSTSIZE +# define UT_HOSTSIZE 16 +# endif /* UT_HOSTSIZE */ +# ifndef UT_LINESIZE +# define UT_LINESIZE 12 +# endif /* UT_LINESIZE */ +#endif +#if defined(hpux) +struct lastlog { + time_t ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; /* same as in utmp */ +}; +#endif /* hpux */ + +/* XXX - time before ignoring lock. Is 1 sec enough? */ +#define LASTLOG_IGNORE_LOCK_TIME 1 + +#define DEFAULT_HOST "" /* "[no.where]" */ +#define DEFAULT_TERM "" /* "tt???" */ +#define LASTLOG_NEVER_WELCOME "Welcome to your new account!" +#define LASTLOG_INTRO "Last login:" +#define LASTLOG_TIME " %s" +#define _LASTLOG_HOST_FORMAT " from %%.%ds" +#define _LASTLOG_LINE_FORMAT " on %%.%ds" +#define LASTLOG_TAIL "" +#define LASTLOG_MAXSIZE (sizeof(LASTLOG_INTRO)+0 \ + +sizeof(LASTLOG_TIME)+strlen(the_time) \ + +sizeof(_LASTLOG_HOST_FORMAT)+UT_HOSTSIZE \ + +sizeof(_LASTLOG_LINE_FORMAT)+UT_LINESIZE \ + +sizeof(LASTLOG_TAIL)) + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_SESSION + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* some syslogging */ + +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-lastlog", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define LASTLOG_DATE 01 /* display the date of the last login */ +#define LASTLOG_HOST 02 /* display the last host used (if set) */ +#define LASTLOG_LINE 04 /* display the last terminal used */ +#define LASTLOG_NEVER 010 /* display a welcome message for first login */ +#define LASTLOG_DEBUG 020 /* send info to syslog(3) */ +#define LASTLOG_QUIET 040 /* keep quiet about things */ + +static int _pam_parse(int flags, int argc, const char **argv) +{ + int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE); + + /* does the appliction require quiet? */ + if (flags & PAM_SILENT) { + ctrl |= LASTLOG_QUIET; + } + + /* step through arguments */ + for (; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) { + ctrl |= LASTLOG_DEBUG; + } else if (!strcmp(*argv,"nodate")) { + ctrl |= ~LASTLOG_DATE; + } else if (!strcmp(*argv,"noterm")) { + ctrl |= ~LASTLOG_LINE; + } else if (!strcmp(*argv,"nohost")) { + ctrl |= ~LASTLOG_HOST; + } else if (!strcmp(*argv,"silent")) { + ctrl |= LASTLOG_QUIET; + } else if (!strcmp(*argv,"never")) { + ctrl |= LASTLOG_NEVER; + } else { + _log_err(LOG_ERR,"unknown option; %s",*argv); + } + } + + D(("ctrl = %o", ctrl)); + return ctrl; +} + +/* a front end for conversations */ + +static int converse(pam_handle_t *pamh, int ctrl, int nargs + , struct pam_message **message + , struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse")); + + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS ) { + + retval = conv->conv(nargs, ( const struct pam_message ** ) message + , response, conv->appdata_ptr); + + D(("returned from application's conversation function")); + + if (retval != PAM_SUCCESS && (ctrl & LASTLOG_DEBUG) ) { + _log_err(LOG_DEBUG, "conversation failure [%s]" + , pam_strerror(pamh, retval)); + } + + } else { + _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" + , pam_strerror(pamh, retval)); + } + + D(("ready to return from module conversation")); + + return retval; /* propagate error status */ +} + +static int make_remark(pam_handle_t *pamh, int ctrl, const char *remark) +{ + int retval; + + if (!(ctrl & LASTLOG_QUIET)) { + struct pam_message msg[1], *mesg[1]; + struct pam_response *resp=NULL; + + mesg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = remark; + + retval = converse(pamh, ctrl, 1, mesg, &resp); + + msg[0].msg = NULL; + if (resp) { + _pam_drop_reply(resp, 1); + } + } else { + D(("keeping quiet")); + retval = PAM_SUCCESS; + } + + D(("returning %s", pam_strerror(pamh, retval))); + return retval; +} + +/* + * Values for the announce flags.. + */ + +static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) +{ + struct flock last_lock; + struct lastlog last_login; + int retval = PAM_SESSION_ERR; + int last_fd; + + /* obtain the last login date and all the relevant info */ + last_fd = open(_PATH_LASTLOG, O_RDWR); + if (last_fd < 0) { + D(("unable to open the %s file", _PATH_LASTLOG)); + if (announce & LASTLOG_DEBUG) { + _log_err(LOG_DEBUG, "unable to open %s file", _PATH_LASTLOG); + } + retval = PAM_PERM_DENIED; + } else { + int win; + + /* read the lastlogin file - for this uid */ + (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET); + + memset(&last_lock, 0, sizeof(last_lock)); + last_lock.l_type = F_RDLCK; + last_lock.l_whence = SEEK_SET; + last_lock.l_start = sizeof(last_login) * (off_t) uid; + last_lock.l_len = sizeof(last_login); + + if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) { + D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); + _log_err(LOG_ALERT, "%s file is locked/read", _PATH_LASTLOG); + sleep(LASTLOG_IGNORE_LOCK_TIME); + } + + win = ( read(last_fd, &last_login, sizeof(last_login)) + == sizeof(last_login) ); + + last_lock.l_type = F_UNLCK; + (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ + + if (!win) { + D(("First login for user uid=%d", _PATH_LASTLOG, uid)); + if (announce & LASTLOG_DEBUG) { + _log_err(LOG_DEBUG, "creating lastlog for uid %d", uid); + } + memset(&last_login, 0, sizeof(last_login)); + } + + /* rewind */ + (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET); + + if (!(announce & LASTLOG_QUIET)) { + if (last_login.ll_time) { + char *the_time; + char *remark; + + the_time = ctime(&last_login.ll_time); + the_time[-1+strlen(the_time)] = '\0'; /* delete '\n' */ + + remark = malloc(LASTLOG_MAXSIZE); + if (remark == NULL) { + D(("no memory for last login remark")); + retval = PAM_BUF_ERR; + } else { + int at; + + /* printing prefix */ + at = sprintf(remark, "%s", LASTLOG_INTRO); + + /* we want the date? */ + if (announce & LASTLOG_DATE) { + at += sprintf(remark+at, LASTLOG_TIME, the_time); + } + + /* we want & have the host? */ + if ((announce & LASTLOG_HOST) + && (last_login.ll_host[0] != '\0')) { + char format[2*sizeof(_LASTLOG_HOST_FORMAT)]; + + (void) sprintf(format, _LASTLOG_HOST_FORMAT + , UT_HOSTSIZE); + D(("format: %s", format)); + at += sprintf(remark+at, format, last_login.ll_host); + _pam_overwrite(format); + } + + /* we want and have the terminal? */ + if ((announce & LASTLOG_LINE) + && (last_login.ll_line[0] != '\0')) { + char format[2*sizeof(_LASTLOG_LINE_FORMAT)]; + + (void) sprintf(format, _LASTLOG_LINE_FORMAT + , UT_LINESIZE); + D(("format: %s", format)); + at += sprintf(remark+at, format, last_login.ll_line); + _pam_overwrite(format); + } + + /* display requested combo */ + sprintf(remark+at, "%s", LASTLOG_TAIL); + + retval = make_remark(pamh, announce, remark); + + /* free all the stuff malloced */ + _pam_overwrite(remark); + _pam_drop(remark); + } + } else if ((!last_login.ll_time) && (announce & LASTLOG_NEVER)) { + D(("this is the first time this user has logged in")); + retval = make_remark(pamh, announce, LASTLOG_NEVER_WELCOME); + } + } else { + D(("no text was requested")); + retval = PAM_SUCCESS; + } + + /* write latest value */ + { + const char *remote_host=NULL + , *terminal_line=DEFAULT_TERM; + + /* set this login date */ + D(("set the most recent login time")); + + (void) time(&last_login.ll_time); /* set the time */ + + /* set the remote host */ + (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); + if (remote_host == NULL) { + remote_host = DEFAULT_HOST; + } + + /* copy to last_login */ + strncpy(last_login.ll_host, remote_host, + sizeof(last_login.ll_host)); + last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0'; + remote_host = NULL; + + /* set the terminal line */ + (void) pam_get_item(pamh, PAM_TTY, (const void **)&terminal_line); + D(("terminal = %s", terminal_line)); + if (terminal_line == NULL) { + terminal_line = DEFAULT_TERM; + } else if ( !strncmp("/dev/", terminal_line, 5) ) { + /* strip leading "/dev/" from tty.. */ + terminal_line += 5; + } + D(("terminal = %s", terminal_line)); + + /* copy to last_login */ + strncpy(last_login.ll_line, terminal_line, + sizeof(last_login.ll_line)); + last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0'; + terminal_line = NULL; + + D(("locking last_log file")); + + /* now we try to lock this file-record exclusively; non-blocking */ + memset(&last_lock, 0, sizeof(last_lock)); + last_lock.l_type = F_WRLCK; + last_lock.l_whence = SEEK_SET; + last_lock.l_start = sizeof(last_login) * (off_t) uid; + last_lock.l_len = sizeof(last_login); + + if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) { + D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); + _log_err(LOG_ALERT, "%s file is locked/write", _PATH_LASTLOG); + sleep(LASTLOG_IGNORE_LOCK_TIME); + } + + D(("writing to the last_log file")); + (void) write(last_fd, &last_login, sizeof(last_login)); + + last_lock.l_type = F_UNLCK; + (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ + D(("unlocked")); + + close(last_fd); /* all done */ + } + D(("all done with last login")); + } + + /* reset the last login structure */ + memset(&last_login, 0, sizeof(last_login)); + + return retval; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc + , const char **argv) +{ + int retval, ctrl; + const char *user; + const struct passwd *pwd; + uid_t uid; + + /* + * this module gets the uid of the PAM_USER. Uses it to display + * last login info and then updates the lastlog for that user. + */ + + ctrl = _pam_parse(flags, argc, argv); + + /* which user? */ + + retval = pam_get_item(pamh, PAM_USER, (const void **)&user); + if (retval != PAM_SUCCESS || user == NULL || *user == '\0') { + _log_err(LOG_NOTICE, "user unknown"); + return PAM_USER_UNKNOWN; + } + + /* what uid? */ + + pwd = getpwnam(user); + if (pwd == NULL) { + D(("couldn't identify user %s", user)); + return PAM_CRED_INSUFFICIENT; + } + uid = pwd->pw_uid; + pwd = NULL; /* tidy up */ + + /* process the current login attempt (indicate last) */ + + retval = last_login_date(pamh, ctrl, uid); + + /* indicate success or failure */ + + uid = -1; /* forget this */ + + return retval; +} + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_lastlog_modstruct = { + "pam_lastlog", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_limits/Makefile b/Linux-PAM/modules/pam_limits/Makefile new file mode 100644 index 00000000..b7462851 --- /dev/null +++ b/Linux-PAM/modules/pam_limits/Makefile @@ -0,0 +1,31 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_limits + +ifeq ($(OS),linux) + +LOCAL_CONFILE=./limits.skel +INSTALLED_CONFILE=$(SCONFIGD)/limits.conf + +DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" +CFLAGS += $(DEFS) + +MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" +MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) +MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age + +include ../Simple.Rules + +else + +include ../dont_makefile + +endif diff --git a/Linux-PAM/modules/pam_limits/README b/Linux-PAM/modules/pam_limits/README new file mode 100644 index 00000000..023b9575 --- /dev/null +++ b/Linux-PAM/modules/pam_limits/README @@ -0,0 +1,107 @@ + +pam_limits module: + Imposing user limits on login. + +THEORY OF OPERATION: + +First, make a root-only-readable file (/etc/security/limits.conf by +default or INSTALLED_CONFILE defined Makefile) that describes the +resource limits you wish to impose. No limits are imposed on UID 0 +accounts. + +Each line describes a limit for a user in the form: + +<domain> <type> <item> <value> + +Where: +<domain> can be: + - an user name + - a group name, with @group syntax + - the wildcard *, for default entry + +<type> can have the three values: + - "soft" for enforcing the soft limits + - "hard" for enforcing hard limits + - "-" for enforcing both soft and hard limits + +<item> can be one of the following: + - core - limits the core file size (KB) + - data - max data size (KB) + - fsize - maximum filesize (KB) + - memlock - max locked-in-memory address space (KB) + - nofile - max number of open files + - rss - max resident set size (KB) + - stack - max stack size (KB) + - cpu - max CPU time (MIN) + - nproc - max number of processes + - as - address space limit + - maxlogins - max number of logins for this user + - maxsyslogins - max number of logins on the system + - priority - lower the priority by given value (value can be -ve) + - locks - max locked files (Linux 2.4 and higher) + +Note, if you specify a type of '-' but neglect to supply the item and +value fields then the module will never enforce any limits on the +specified user/group etc. . + +Please remember that individual limits have priority over group +limits, so if you impose no limits for admin group, but one of the +members in this group has a limits line, the user will have its limits +set according to this line. + +Also, please note that all limit settings are set PER LOGIN. They are +not global, nor are they permanent (they apply for the session only). + +In the LIMITS_FILE, the # character introduces a comment - the rest of the +line is ignored. + +The pam_limits module does its best to report configuration problems found +in LIMITS_FILE via syslog. + +EXAMPLE configuration file: +=========================== +* soft core 0 +* hard rss 10000 +@student hard nproc 20 +@faculty soft nproc 20 +@faculty hard nproc 50 +ftp hard nproc 0 +@student - maxlogins 4 + + +ARGUMENTS RECOGNIZED: + debug verbose logging + + conf=/path/to/file the limits configuration file if different from the + one set at compile time. + + change_uid change real uid to the user for who the limits + are set up. Use this option if you have problems + like login not forking a shell for user who has + no processes. Be warned that something else + may break when you do this. + + utmp_early some broken applications actually allocate a + utmp entry for the user before the user is + admitted to the system. If the service you are + configuring PAM for does this, you can use + this module argument to compensate for this + brokenness. + +MODULE SERVICES PROVIDED: + session _open_session and _close_session (blank) + +USAGE: + For the services you need resources limits (login for example) put a + the following line in /etc/pam.conf as the last line for that + service (usually after the pam_unix session line: + + login session required /lib/security/pam_limits.so + + Replace "login" for each service you are using this module, replace + "/lib/security" path with your real modules path. + +AUTHOR: + Cristian Gafton <gafton@redhat.com> + Thanks to Elliot Lee <sopwith@redhat.com> for his comments on + improving this module, and Jens Sorensen for Linux 2.4 updates. diff --git a/Linux-PAM/modules/pam_limits/limits.skel b/Linux-PAM/modules/pam_limits/limits.skel new file mode 100644 index 00000000..ccb4e103 --- /dev/null +++ b/Linux-PAM/modules/pam_limits/limits.skel @@ -0,0 +1,45 @@ +# /etc/security/limits.conf +# +#Each line describes a limit for a user in the form: +# +#<domain> <type> <item> <value> +# +#Where: +#<domain> can be: +# - an user name +# - a group name, with @group syntax +# - the wildcard *, for default entry +# - the wildcard %, can be also used with %group syntax, +# for maxlogin limit +# +#<type> can have the two values: +# - "soft" for enforcing the soft limits +# - "hard" for enforcing hard limits +# +#<item> can be one of the following: +# - core - limits the core file size (KB) +# - data - max data size (KB) +# - fsize - maximum filesize (KB) +# - memlock - max locked-in-memory address space (KB) +# - nofile - max number of open files +# - rss - max resident set size (KB) +# - stack - max stack size (KB) +# - cpu - max CPU time (MIN) +# - nproc - max number of processes +# - as - address space limit +# - maxlogins - max number of logins for this user +# - priority - the priority to run user process with +# - locks - max number of file locks the user can hold +# +#<domain> <type> <item> <value> +# + +#* soft core 0 +#* hard rss 10000 +#@student hard nproc 20 +#@faculty soft nproc 20 +#@faculty hard nproc 50 +#ftp hard nproc 0 +#@student - maxlogins 4 + +# End of file diff --git a/Linux-PAM/modules/pam_limits/pam_limits.c b/Linux-PAM/modules/pam_limits/pam_limits.c new file mode 100644 index 00000000..6837fdef --- /dev/null +++ b/Linux-PAM/modules/pam_limits/pam_limits.c @@ -0,0 +1,726 @@ +/* + * pam_limits - impose resource limits when opening a user session + * + * 1.6 - modified for PLD (added process priority settings) + * by Marcin Korzonek <mkorz@shadow.eu.org> + * 1.5 - Elliot Lee's "max system logins patch" + * 1.4 - addressed bug in configuration file parser + * 1.3 - modified the configuration file format + * 1.2 - added 'debug' and 'conf=' arguments + * 1.1 - added @group support + * 1.0 - initial release - Linux ONLY + * + * See end for Copyright information + */ + +#if !(defined(linux)) +#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! +#endif + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <errno.h> +#include <syslog.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/resource.h> + +#include <utmp.h> +#ifndef UT_USER /* some systems have ut_name instead of ut_user */ +#define UT_USER ut_user +#endif + +#include <grp.h> +#include <pwd.h> + +/* Module defines */ +#define LINE_LENGTH 1024 + +#define LIMITS_DEF_USER 0 /* limit was set by an user entry */ +#define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */ +#define LIMITS_DEF_DEFAULT 2 /* limit was set by an default entry */ +#define LIMITS_DEF_NONE 3 /* this limit was not set yet */ +#define LIMITS_DEF_ALL 4 /* limit was set by an default entry */ +#define LIMITS_DEF_ALLGROUP 5 /* limit was set by a group entry */ + +static const char *limits_def_names[] = { + "USER", + "GROUP", + "DEFAULT", + "NONE", + NULL, +}; + +struct user_limits_struct { + int src_soft; + int src_hard; + struct rlimit limit; +}; + +/* internal data */ +struct pam_limit_s { + int login_limit; /* the max logins limit */ + int login_limit_def; /* which entry set the login limit */ + int flag_numsyslogins; /* whether to limit logins only for a + specific user or to count all logins */ + int priority; /* the priority to run user process with */ + int supported[RLIM_NLIMITS]; + struct user_limits_struct limits[RLIM_NLIMITS]; + char conf_file[BUFSIZ]; + int utmp_after_pam_call; +}; + +#define LIMIT_LOGIN RLIM_NLIMITS+1 +#define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2 + +#define LIMIT_PRI RLIM_NLIMITS+3 + +#define LIMIT_SOFT 1 +#define LIMIT_HARD 2 + +#define PAM_SM_SESSION + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* logging */ +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pam_limits", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x0001 +#define PAM_DO_SETREUID 0x0002 +#define PAM_UTMP_EARLY 0x0004 + +static int _pam_parse(int argc, const char **argv, struct pam_limit_s *pl) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) { + ctrl |= PAM_DEBUG_ARG; + } else if (!strncmp(*argv,"conf=",5)) { + strncpy(pl->conf_file,*argv+5,sizeof(pl->conf_file)-1); + } else if (!strncmp(*argv,"change_uid",10)) { + ctrl |= PAM_DO_SETREUID; + } else if (!strcmp(*argv,"utmp_early")) { + ctrl |= PAM_UTMP_EARLY; + } else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + pl->conf_file[sizeof(pl->conf_file) - 1] = '\0'; + + return ctrl; +} + + +/* limits stuff */ +#ifdef DEFAULT_CONF_FILE +# define LIMITS_FILE DEFAULT_CONF_FILE +#else +# define LIMITS_FILE "/etc/security/limits.conf" +#endif + +#define LIMITED_OK 0 /* limit setting appeared to work */ +#define LIMIT_ERR 1 /* error setting a limit */ +#define LOGIN_ERR 2 /* too many logins err */ + +/* checks if a user is on a list of members of the GID 0 group */ +static int is_on_list(char * const *list, const char *member) +{ + while (*list) { + if (strcmp(*list, member) == 0) + return 1; + list++; + } + return 0; +} + +/* + * Checks if a user is a member of a group - return non-zero if + * the user is in the group. + */ +static int is_in_group(const char *user_name, const char *group_name) +{ + struct passwd *pwd; + struct group *grp, *pgrp; + char uname[LINE_LENGTH], gname[LINE_LENGTH]; + + if (!user_name || !strlen(user_name)) + return 0; + if (!group_name || !strlen(group_name)) + return 0; + memset(uname, 0, sizeof(uname)); + strncpy(uname, user_name, sizeof(uname)-1); + memset(gname, 0, sizeof(gname)); + strncpy(gname, group_name, sizeof(gname)-1); + + pwd = getpwnam(uname); + if (!pwd) + return 0; + + /* the info about this group */ + grp = getgrnam(gname); + if (!grp) + return 0; + + /* first check: is a member of the group_name group ? */ + if (is_on_list(grp->gr_mem, uname)) + return 1; + + /* next check: user primary group is group_name ? */ + pgrp = getgrgid(pwd->pw_gid); + if (!pgrp) + return 0; + if (!strcmp(pgrp->gr_name, gname)) + return 1; + + return 0; +} + +/* Counts the number of user logins and check against the limit*/ +static int check_logins(const char *name, int limit, int ctrl, + struct pam_limit_s *pl) +{ + struct utmp *ut; + unsigned int count; + + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "checking logins for '%s' (maximum of %d)\n", + name, limit); + } + + if (limit < 0) + return 0; /* no limits imposed */ + if (limit == 0) /* maximum 0 logins ? */ { + _pam_log(LOG_WARNING, "No logins allowed for '%s'\n", name); + return LOGIN_ERR; + } + + setutent(); + + /* Because there is no definition about when an application + actually adds a utmp entry, some applications bizarrely do the + utmp call before the have PAM authenticate them to the system: + you're logged it, sort of...? Anyway, you can use the + "utmp_early" module argument in your PAM config file to make + allowances for this sort of problem. (There should be a PAM + standard for this, since if a module wants to actually map a + username then any early utmp entry will be for the unmapped + name = broken.) */ + + if (ctrl & PAM_UTMP_EARLY) { + count = 0; + } else { + count = 1; + } + + while((ut = getutent())) { +#ifdef USER_PROCESS + if (ut->ut_type != USER_PROCESS) { + continue; + } +#endif + if (ut->UT_USER[0] == '\0') { + continue; + } + if (!pl->flag_numsyslogins) { + if (((pl->login_limit_def == LIMITS_DEF_USER) + || (pl->login_limit_def == LIMITS_DEF_GROUP) + || (pl->login_limit_def == LIMITS_DEF_DEFAULT)) + && strncmp(name, ut->UT_USER, sizeof(ut->UT_USER)) != 0) { + continue; + } + if ((pl->login_limit_def == LIMITS_DEF_ALLGROUP) + && !is_in_group(ut->UT_USER, name)) { + continue; + } + } + if (++count > limit) { + break; + } + } + endutent(); + if (count > limit) { + if (name) { + _pam_log(LOG_WARNING, "Too many logins (max %d) for %s", + limit, name); + } else { + _pam_log(LOG_WARNING, "Too many system logins (max %d)", limit); + } + return LOGIN_ERR; + } + return 0; +} + +static int init_limits(struct pam_limit_s *pl) +{ + int i; + int retval = PAM_SUCCESS; + + D(("called.")); + + for(i = 0; i < RLIM_NLIMITS; i++) { + int r = getrlimit(i, &pl->limits[i].limit); + if (r == -1) { + if (errno == EINVAL) { + pl->supported[i] = 0; + } else { + retval = !PAM_SUCCESS; + } + } else { + pl->supported[i] = 1; + pl->limits[i].src_soft = LIMITS_DEF_NONE; + pl->limits[i].src_hard = LIMITS_DEF_NONE; + } + } + + pl->priority = 0; + pl->login_limit = -2; + pl->login_limit_def = LIMITS_DEF_NONE; + + return retval; +} + +static void process_limit(int source, const char *lim_type, + const char *lim_item, const char *lim_value, + int ctrl, struct pam_limit_s *pl) +{ + int limit_item; + int limit_type = 0; + long limit_value; + const char **endptr = &lim_value; + const char *value_orig = lim_value; + + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "%s: processing %s %s %s for %s\n", + __FUNCTION__,lim_type,lim_item,lim_value, + limits_def_names[source]); + + if (strcmp(lim_item, "cpu") == 0) + limit_item = RLIMIT_CPU; + else if (strcmp(lim_item, "fsize") == 0) + limit_item = RLIMIT_FSIZE; + else if (strcmp(lim_item, "data") == 0) + limit_item = RLIMIT_DATA; + else if (strcmp(lim_item, "stack") == 0) + limit_item = RLIMIT_STACK; + else if (strcmp(lim_item, "core") == 0) + limit_item = RLIMIT_CORE; + else if (strcmp(lim_item, "rss") == 0) + limit_item = RLIMIT_RSS; + else if (strcmp(lim_item, "nproc") == 0) + limit_item = RLIMIT_NPROC; + else if (strcmp(lim_item, "nofile") == 0) + limit_item = RLIMIT_NOFILE; + else if (strcmp(lim_item, "memlock") == 0) + limit_item = RLIMIT_MEMLOCK; + else if (strcmp(lim_item, "as") == 0) + limit_item = RLIMIT_AS; +#ifdef RLIMIT_LOCKS + else if (strcmp(lim_item, "locks") == 0) + limit_item = RLIMIT_LOCKS; +#endif + else if (strcmp(lim_item, "maxlogins") == 0) { + limit_item = LIMIT_LOGIN; + pl->flag_numsyslogins = 0; + } else if (strcmp(lim_item, "maxsyslogins") == 0) { + limit_item = LIMIT_NUMSYSLOGINS; + pl->flag_numsyslogins = 1; + } else if (strcmp(lim_item, "priority") == 0) { + limit_item = LIMIT_PRI; + } else { + _pam_log(LOG_DEBUG,"unknown limit item '%s'", lim_item); + return; + } + + if (strcmp(lim_type,"soft")==0) + limit_type=LIMIT_SOFT; + else if (strcmp(lim_type, "hard")==0) + limit_type=LIMIT_HARD; + else if (strcmp(lim_type,"-")==0) + limit_type=LIMIT_SOFT | LIMIT_HARD; + else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) { + _pam_log(LOG_DEBUG,"unknown limit type '%s'", lim_type); + return; + } + + /* + * there is a warning here because the library prototype for this + * function is incorrect. + */ + limit_value = strtol(lim_value, endptr, 10); + + /* special case value when limiting logins */ + if (limit_value == 0 && value_orig == *endptr) { /* no chars read */ + if (strcmp(lim_value,"-") != 0) { + _pam_log(LOG_DEBUG,"wrong limit value '%s'", lim_value); + return; + } else + if (limit_item != LIMIT_LOGIN) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, + "'-' limit value valid for maxlogins type only"); + return; + } else + limit_value = -1; + } + + /* one more special case when limiting logins */ + if ((source == LIMITS_DEF_ALL || source == LIMITS_DEF_ALLGROUP) + && (limit_item != LIMIT_LOGIN)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, + "'%%' domain valid for maxlogins type only"); + return; + } + + switch(limit_item) { + case RLIMIT_CPU: + limit_value *= 60; + break; + case RLIMIT_FSIZE: + case RLIMIT_DATA: + case RLIMIT_STACK: + case RLIMIT_CORE: + case RLIMIT_RSS: + case RLIMIT_MEMLOCK: + case RLIMIT_AS: + limit_value *= 1024; + break; + } + + if ( (limit_item != LIMIT_LOGIN) + && (limit_item != LIMIT_NUMSYSLOGINS) + && (limit_item != LIMIT_PRI) ) { + if (limit_type & LIMIT_SOFT) { + if (pl->limits[limit_item].src_soft < source) { + return; + } else { + pl->limits[limit_item].limit.rlim_cur = limit_value; + pl->limits[limit_item].src_soft = source; + } + } + if (limit_type & LIMIT_HARD) { + if (pl->limits[limit_item].src_hard < source) { + return; + } else { + pl->limits[limit_item].limit.rlim_max = limit_value; + pl->limits[limit_item].src_hard = source; + } + } + } else { + /* recent kernels support negative priority limits (=raise priority) */ + + if (limit_item == LIMIT_PRI) { + pl->priority = limit_value; + } else { + if (pl->login_limit_def < source) { + return; + } else { + pl->login_limit = limit_value; + pl->login_limit_def = source; + } + } + } + return; +} + +static int parse_config_file(const char *uname, int ctrl, + struct pam_limit_s *pl) +{ + FILE *fil; + char buf[LINE_LENGTH]; + +#define CONF_FILE (pl->conf_file[0])?pl->conf_file:LIMITS_FILE + /* check for the LIMITS_FILE */ + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"reading settings from '%s'", CONF_FILE); + fil = fopen(CONF_FILE, "r"); + if (fil == NULL) { + _pam_log (LOG_WARNING, "can not read settings from %s", CONF_FILE); + return PAM_SERVICE_ERR; + } +#undef CONF_FILE + + /* init things */ + memset(buf, 0, sizeof(buf)); + /* start the show */ + while (fgets(buf, LINE_LENGTH, fil) != NULL) { + char domain[LINE_LENGTH]; + char ltype[LINE_LENGTH]; + char item[LINE_LENGTH]; + char value[LINE_LENGTH]; + int i,j; + char *tptr; + + tptr = buf; + /* skip the leading white space */ + while (*tptr && isspace(*tptr)) + tptr++; + strncpy(buf, tptr, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + /* Rip off the comments */ + tptr = strchr(buf,'#'); + if (tptr) + *tptr = '\0'; + /* Rip off the newline char */ + tptr = strchr(buf,'\n'); + if (tptr) + *tptr = '\0'; + /* Anything left ? */ + if (!strlen(buf)) { + memset(buf, 0, sizeof(buf)); + continue; + } + + memset(domain, 0, sizeof(domain)); + memset(ltype, 0, sizeof(ltype)); + memset(item, 0, sizeof(item)); + memset(value, 0, sizeof(value)); + + i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value); + D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]", + i, domain, ltype, item, value)); + + for(j=0; j < strlen(domain); j++) + domain[j]=tolower(domain[j]); + for(j=0; j < strlen(ltype); j++) + ltype[j]=tolower(ltype[j]); + for(j=0; j < strlen(item); j++) + item[j]=tolower(item[j]); + for(j=0; j < strlen(value); j++) + value[j]=tolower(value[j]); + + if (i == 4) { /* a complete line */ + if (strcmp(uname, domain) == 0) /* this user have a limit */ + process_limit(LIMITS_DEF_USER, ltype, item, value, ctrl, pl); + else if (domain[0]=='@') { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "checking if %s is in group %s", + uname, domain + 1); + } + if (is_in_group(uname, domain+1)) + process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl, + pl); + } else if (domain[0]=='%') { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "checking if %s is in group %s", + uname, domain + 1); + } + if (strcmp(domain,"%") == 0) + process_limit(LIMITS_DEF_ALL, ltype, item, value, ctrl, + pl); + else if (is_in_group(uname, domain+1)) + process_limit(LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, + pl); + } else if (strcmp(domain, "*") == 0) + process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, + pl); + } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */ + if (strcmp(uname, domain) == 0) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "no limits for '%s'", uname); + } + fclose(fil); + return PAM_IGNORE; + } else if (domain[0] == '@' && is_in_group(uname, domain+1)) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "no limits for '%s' in group '%s'", + uname, domain+1); + } + fclose(fil); + return PAM_IGNORE; + } + } else { + _pam_log(LOG_DEBUG,"invalid line '%s' - skipped", buf); + } + } + fclose(fil); + return PAM_SUCCESS; +} + +static int setup_limits(const char * uname, uid_t uid, int ctrl, + struct pam_limit_s *pl) +{ + int i; + int status; + int retval = LIMITED_OK; + + if (uid == 0) { + /* do not impose limits (+ve limits anyway) on the superuser */ + if (pl->priority > 0) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "user '%s' has UID 0 - no limits imposed", + uname); + } + pl->priority = 0; + } + } + + for (i=0, status=LIMITED_OK; i<RLIM_NLIMITS; i++) { + if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max) + pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max; + if (!pl->supported[i]) { + /* skip it if its not known to the system */ + continue; + } + status |= setrlimit(i, &pl->limits[i].limit); + } + + if (status) { + retval = LIMIT_ERR; + } + + status = setpriority(PRIO_PROCESS, 0, pl->priority); + if (status != 0) { + retval = LIMIT_ERR; + } + + if (uid == 0) { + D(("skip login limit check for uid=0")); + } else if (pl->login_limit > 0) { + if (check_logins(uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) { + retval |= LOGIN_ERR; + } + } else if (pl->login_limit == 0) { + retval |= LOGIN_ERR; + } + + return retval; +} + +/* now the session stuff */ +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval; + char *user_name; + struct passwd *pwd; + int ctrl; + struct pam_limit_s pl; + + D(("called.")); + + memset(&pl, 0, sizeof(pl)); + + ctrl = _pam_parse(argc, argv, &pl); + retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + _pam_log(LOG_CRIT, "open_session - error recovering username"); + return PAM_SESSION_ERR; + } + + pwd = getpwnam(user_name); + if (!pwd) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_WARNING, "open_session username '%s' does not exist", + user_name); + return PAM_SESSION_ERR; + } + + retval = init_limits(&pl); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_WARNING, "cannot initialize"); + return PAM_IGNORE; + } + + retval = parse_config_file(pwd->pw_name, ctrl, &pl); + if (retval == PAM_IGNORE) { + D(("the configuration file has an applicable '<domain> -' entry")); + return PAM_SUCCESS; + } + if (retval != PAM_SUCCESS) { + _pam_log(LOG_WARNING, "error parsing the configuration file"); + return PAM_IGNORE; + } + + if (ctrl & PAM_DO_SETREUID) { + setreuid(pwd->pw_uid, -1); + } + retval = setup_limits(pwd->pw_name, pwd->pw_uid, ctrl, &pl); + if (retval != LIMITED_OK) { + return PAM_PERM_DENIED; + } + + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + /* nothing to do */ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_limits_modstruct = { + "pam_limits", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL +}; +#endif + +/* + * Copyright (c) Cristian Gafton, 1996-1997, <gafton@redhat.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_listfile/Makefile b/Linux-PAM/modules/pam_listfile/Makefile new file mode 100644 index 00000000..5a3d6957 --- /dev/null +++ b/Linux-PAM/modules/pam_listfile/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_listfile + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_listfile/README b/Linux-PAM/modules/pam_listfile/README new file mode 100644 index 00000000..b65e7dbb --- /dev/null +++ b/Linux-PAM/modules/pam_listfile/README @@ -0,0 +1,25 @@ +SUMMARY: + pam_listfile: + Checks a specified item against a list in a file. + Options: + * item=[tty|user|rhost|ruser|group|shell] + * sense=[allow|deny] (action to take if found in file, + if the item is NOT found in the file, then + the opposite action is requested) + * file=/the/file/to/get/the/list/from + * onerr=[succeed|fail] (if something weird happens + such as unable to open the file, what to do?) + * apply=[user|@group] + restrict the user class for which the restriction + apply. Note that with item=[user|ruser|group] this + does not make sense, but for item=[tty|rhost|shell] + it have a meaning. (Cristian Gafton) + + Also checks to make sure that the list file is a plain + file and not world writable. + + - Elliot Lee <sopwith@redhat.com>, Red Hat Software. + v0.9 August 16, 1996. + +BUGS: + Bugs? diff --git a/Linux-PAM/modules/pam_listfile/pam_listfile.c b/Linux-PAM/modules/pam_listfile/pam_listfile.c new file mode 100644 index 00000000..934b51fb --- /dev/null +++ b/Linux-PAM/modules/pam_listfile/pam_listfile.c @@ -0,0 +1,439 @@ +/* + * $Id: pam_listfile.c,v 1.1.1.2 2002/09/15 20:08:51 hartmans Exp $ + * + */ + +/* + * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996. + * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11 + * + * This code began life as the pam_rootok module. + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> + +#ifdef DEBUG +#include <assert.h> +#endif + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* some syslogging */ + +#define LOCAL_LOG_PREFIX "PAM-listfile: " + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsyslog(LOG_AUTH | err, format, args); + va_end(args); +} + +/* checks if a user is on a list of members */ +static int is_on_list(char * const *list, const char *member) +{ + while (*list) { + if (strcmp(*list, member) == 0) + return 1; + list++; + } + return 0; +} + +/* Checks if a user is a member of a group */ +static int is_on_group(const char *user_name, const char *group_name) +{ + struct passwd *pwd; + struct group *grp, *pgrp; + char uname[BUFSIZ], gname[BUFSIZ]; + + if (!strlen(user_name)) + return 0; + if (!strlen(group_name)) + return 0; + bzero(uname, sizeof(uname)); + strncpy(uname, user_name, sizeof(uname)-1); + bzero(gname, sizeof(gname)); + strncpy(gname, group_name, sizeof(gname)-1); + + pwd = getpwnam(uname); + if (!pwd) + return 0; + + /* the info about this group */ + grp = getgrnam(gname); + if (!grp) + return 0; + + /* first check: is a member of the group_name group ? */ + if (is_on_list(grp->gr_mem, uname)) + return 1; + + /* next check: user primary group is group_name ? */ + pgrp = getgrgid(pwd->pw_gid); + if (!pgrp) + return 0; + if (!strcmp(pgrp->gr_name, gname)) + return 1; + + return 0; +} + +/* --- authentication management functions (only) --- */ + +/* Extended Items that are not directly available via pam_get_item() */ +#define EI_GROUP (1 << 0) +#define EI_SHELL (1 << 1) + +/* Constants for apply= parameter */ +#define APPLY_TYPE_NULL 0 +#define APPLY_TYPE_NONE 1 +#define APPLY_TYPE_USER 2 +#define APPLY_TYPE_GROUP 3 + +#define LESSER(a, b) ((a) < (b) ? (a) : (b)) + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2; + const char *citemp; + char *ifname=NULL; + char aline[256]; + char mybuf[256],myval[256]; + struct stat fileinfo; + FILE *inf; + char apply_val[256]; + int apply_type; + + /* Stuff for "extended" items */ + struct passwd *userinfo; + struct group *grpinfo; + char *itemlist[256]; /* Maximum of 256 items */ + + D(("called.")); + + apply_type=APPLY_TYPE_NULL; + memset(apply_val,0,sizeof(apply_val)); + + for(i=0; i < argc; i++) { + { + const char *junk; + + memset(mybuf,'\0',sizeof(mybuf)); + memset(myval,'\0',sizeof(mybuf)); + junk = strchr(argv[i], '='); + if((junk == NULL) || (junk - argv[i]) >= sizeof(mybuf)) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Bad option: \"%s\"", + argv[i]); + continue; + } + strncpy(mybuf, argv[i], LESSER(junk - argv[i], sizeof(mybuf) - 1)); + strncpy(myval, junk + 1, sizeof(myval) - 1); + } + if(!strcmp(mybuf,"onerr")) + if(!strcmp(myval,"succeed")) + onerr = PAM_SUCCESS; + else if(!strcmp(myval,"fail")) + onerr = PAM_SERVICE_ERR; + else + return PAM_SERVICE_ERR; + else if(!strcmp(mybuf,"sense")) + if(!strcmp(myval,"allow")) + sense=0; + else if(!strcmp(myval,"deny")) + sense=1; + else + return onerr; + else if(!strcmp(mybuf,"file")) { + ifname = (char *)malloc(strlen(myval)+1); + strcpy(ifname,myval); + } else if(!strcmp(mybuf,"item")) + if(!strcmp(myval,"user")) + citem = PAM_USER; + else if(!strcmp(myval,"tty")) + citem = PAM_TTY; + else if(!strcmp(myval,"rhost")) + citem = PAM_RHOST; + else if(!strcmp(myval,"ruser")) + citem = PAM_RUSER; + else { /* These items are related to the user, but are not + directly gettable with pam_get_item */ + citem = PAM_USER; + if(!strcmp(myval,"group")) + extitem = EI_GROUP; + else if(!strcmp(myval,"shell")) + extitem = EI_SHELL; + else + citem = 0; + } else if(!strcmp(mybuf,"apply")) { + apply_type=APPLY_TYPE_NONE; + memset(apply_val,'\0',sizeof(apply_val)); + if (myval[0]=='@') { + apply_type=APPLY_TYPE_GROUP; + strncpy(apply_val,myval+1,sizeof(apply_val)-1); + } else { + apply_type=APPLY_TYPE_USER; + strncpy(apply_val,myval,sizeof(apply_val)-1); + } + } else { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Unknown option: %s",mybuf); + return onerr; + } + } + + if(!citem) { + _pam_log(LOG_ERR, + LOCAL_LOG_PREFIX "Unknown item or item not specified"); + return onerr; + } else if(!ifname) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "List filename not specified"); + return onerr; + } else if(sense == 2) { + _pam_log(LOG_ERR, + LOCAL_LOG_PREFIX "Unknown sense or sense not specified"); + return onerr; + } else if( + (apply_type==APPLY_TYPE_NONE) || + ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0')) + ) { + _pam_log(LOG_ERR, + LOCAL_LOG_PREFIX "Invalid usage for apply= parameter"); + return onerr; + } + + /* Check if it makes sense to use the apply= parameter */ + if (apply_type != APPLY_TYPE_NULL) { + if((citem==PAM_USER) || (citem==PAM_RUSER)) { + _pam_log(LOG_WARNING, + LOCAL_LOG_PREFIX "Non-sense use for apply= parameter"); + apply_type=APPLY_TYPE_NULL; + } + if(extitem && (extitem==EI_GROUP)) { + _pam_log(LOG_WARNING, + LOCAL_LOG_PREFIX "Non-sense use for apply= parameter"); + apply_type=APPLY_TYPE_NULL; + } + } + + /* Short-circuit - test if this session apply for this user */ + { + const char *user_name; + int rval; + + rval=pam_get_user(pamh,&user_name,NULL); + if((rval==PAM_SUCCESS) && user_name[0]) { + /* Got it ? Valid ? */ + if(apply_type==APPLY_TYPE_USER) { + if(strcmp(user_name, apply_val)) { + /* Does not apply to this user */ +#ifdef DEBUG + _pam_log(LOG_DEBUG, + LOCAL_LOG_PREFIX "don't apply: apply=%s, user=%s", + apply_val,user_name); +#endif /* DEBUG */ + return PAM_IGNORE; + } + } else if(apply_type==APPLY_TYPE_GROUP) { + if(!is_on_group(user_name,apply_val)) { + /* Not a member of apply= group */ +#ifdef DEBUG + _pam_log(LOG_DEBUG, + LOCAL_LOG_PREFIX + "don't apply: %s not a member of group %s", + user_name,apply_val); +#endif /* DEBUG */ + return PAM_IGNORE; + } + } + } + } + + retval = pam_get_item(pamh,citem,(const void **)&citemp); + if(retval != PAM_SUCCESS) { + return onerr; + } + if((citem == PAM_USER) && !citemp) { + pam_get_user(pamh,&citemp,NULL); + if (retval != PAM_SUCCESS) + return PAM_SERVICE_ERR; + } + + if(!citemp || (strlen(citemp) <= 0)) { + /* The item was NULL - we are sure not to match */ + return sense?PAM_SUCCESS:PAM_AUTH_ERR; + } + + if(extitem) { + switch(extitem) { + case EI_GROUP: + userinfo = getpwnam(citemp); + if (userinfo == NULL) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", + citemp); + return onerr; + } + grpinfo = getgrgid(userinfo->pw_gid); + if (grpinfo == NULL) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getgrgid(%d) failed", + (int)userinfo->pw_gid); + return onerr; + } + itemlist[0] = x_strdup(grpinfo->gr_name); + setgrent(); + for (i=1; (i < sizeof(itemlist)/sizeof(itemlist[0])-1) && + (grpinfo = getgrent()); ) { + if (is_on_list(grpinfo->gr_mem,citemp)) { + itemlist[i++] = x_strdup(grpinfo->gr_name); + } + } + endgrent(); + itemlist[i] = NULL; + break; + case EI_SHELL: + /* Assume that we have already gotten PAM_USER in + pam_get_item() - a valid assumption since citem + gets set to PAM_USER in the extitem switch */ + userinfo = getpwnam(citemp); + if (userinfo == NULL) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", + citemp); + return onerr; + } + citemp = userinfo->pw_shell; + break; + default: + _pam_log(LOG_ERR, + LOCAL_LOG_PREFIX + "Internal weirdness, unknown extended item %d", + extitem); + return onerr; + } + } +#ifdef DEBUG + _pam_log(LOG_INFO, + LOCAL_LOG_PREFIX + "Got file = %s, item = %d, value = %s, sense = %d", + ifname, citem, citemp, sense); +#endif + if(lstat(ifname,&fileinfo)) { + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Couldn't open %s",ifname); + return onerr; + } + + if((fileinfo.st_mode & S_IWOTH) + || !S_ISREG(fileinfo.st_mode)) { + /* If the file is world writable or is not a + normal file, return error */ + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX + "%s is either world writable or not a normal file", + ifname); + return PAM_AUTH_ERR; + } + + inf = fopen(ifname,"r"); + if(inf == NULL) { /* Check that we opened it successfully */ + if (onerr == PAM_SERVICE_ERR) { + /* Only report if it's an error... */ + _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Error opening %s", ifname); + } + return onerr; + } + /* There should be no more errors from here on */ + retval=PAM_AUTH_ERR; + /* This loop assumes that PAM_SUCCESS == 0 + and PAM_AUTH_ERR != 0 */ +#ifdef DEBUG + assert(PAM_SUCCESS == 0); + assert(PAM_AUTH_ERR != 0); +#endif + if(extitem == EI_GROUP) { + while((fgets(aline,255,inf) != NULL) + && retval) { + if(aline[strlen(aline) - 1] == '\n') + aline[strlen(aline) - 1] = '\0'; + for(i=0;itemlist[i];) + /* If any of the items match, strcmp() == 0, and we get out + of this loop */ + retval = (strcmp(aline,itemlist[i++]) && retval); + } + for(i=0;itemlist[i];) + free(itemlist[i++]); + } else { + while((fgets(aline,255,inf) != NULL) + && retval) { + if(aline[strlen(aline) - 1] == '\n') + aline[strlen(aline) - 1] = '\0'; + retval = strcmp(aline,citemp); + } + } + fclose(inf); + free(ifname); + if ((sense && retval) || (!sense && !retval)) { +#ifdef DEBUG + _pam_log(LOG_INFO, LOCAL_LOG_PREFIX + "Returning PAM_SUCCESS, retval = %d", retval); +#endif + return PAM_SUCCESS; + } + else { + const char *service, *user_name; +#ifdef DEBUG + _pam_log(LOG_INFO,LOCAL_LOG_PREFIX + "Returning PAM_AUTH_ERR, retval = %d", retval); +#endif + (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); + (void) pam_get_user(pamh, &user_name, NULL); + _pam_log(LOG_ALERT,LOCAL_LOG_PREFIX "Refused user %s for service %s", + user_name, service); + return PAM_AUTH_ERR; + } +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_listfile_modstruct = { + "pam_listfile", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ + diff --git a/Linux-PAM/modules/pam_mail/Makefile b/Linux-PAM/modules/pam_mail/Makefile new file mode 100644 index 00000000..d5e5c44a --- /dev/null +++ b/Linux-PAM/modules/pam_mail/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_mail + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_mail/README b/Linux-PAM/modules/pam_mail/README new file mode 100644 index 00000000..155bd1db --- /dev/null +++ b/Linux-PAM/modules/pam_mail/README @@ -0,0 +1,17 @@ +This is the README for pam_mail +------------------------------- + +This PAM module tells the User that he has new/unread email. + +Options for: +auth: for authentication it provides pam_authenticate() and + pam_setcred() hooks. + + "debug" write more information to syslog + "dir=maildir" users mailbox is maildir/<login> + "hash=count" mail directory hash depth + "close" print message also on logout + "nopen" print message not on login + "noenv" don't set the MAIL environment variable + "empty" also print message if user has no mail + diff --git a/Linux-PAM/modules/pam_mail/pam_mail.c b/Linux-PAM/modules/pam_mail/pam_mail.c new file mode 100644 index 00000000..d63e79b1 --- /dev/null +++ b/Linux-PAM/modules/pam_mail/pam_mail.c @@ -0,0 +1,499 @@ +/* pam_mail module */ + +/* + * $Id: pam_mail.c,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 + * $HOME additions by David Kinchlea <kinch@kinch.ark.com> 1997/1/7 + * mailhash additions by Chris Adams <cadams@ro.com> 1998/7/11 + */ + +#include <security/_pam_aconf.h> + +#include <ctype.h> +#include <pwd.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <dirent.h> + +#ifdef WANT_PWDB +#include <pwdb/pwdb_public.h> +#endif + +#define DEFAULT_MAIL_DIRECTORY PAM_PATH_MAILDIR +#define MAIL_FILE_FORMAT "%s%s/%s" +#define MAIL_ENV_NAME "MAIL" +#define MAIL_ENV_FORMAT MAIL_ENV_NAME "=%s" +#define YOUR_MAIL_VERBOSE_FORMAT "You have %s mail in %s." +#define YOUR_MAIL_STANDARD_FORMAT "You have %smail." +#define NO_MAIL_STANDARD_FORMAT "No mail." + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_SESSION +#define PAM_SM_AUTH + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* some syslogging */ + +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-mail", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x0001 +#define PAM_NO_LOGIN 0x0002 +#define PAM_LOGOUT_TOO 0x0004 +#define PAM_NEW_MAIL_DIR 0x0010 +#define PAM_MAIL_SILENT 0x0020 +#define PAM_NO_ENV 0x0040 +#define PAM_HOME_MAIL 0x0100 +#define PAM_EMPTY_TOO 0x0200 +#define PAM_STANDARD_MAIL 0x0400 +#define PAM_QUIET_MAIL 0x1000 + +static int _pam_parse(int flags, int argc, const char **argv, char **maildir, + int *hashcount) +{ + int ctrl=0; + + if (flags & PAM_SILENT) { + ctrl |= PAM_MAIL_SILENT; + } + + *hashcount = 0; + + /* step through arguments */ + for (; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strcmp(*argv,"quiet")) + ctrl |= PAM_QUIET_MAIL; + else if (!strcmp(*argv,"standard")) + ctrl |= PAM_STANDARD_MAIL | PAM_EMPTY_TOO; + else if (!strncmp(*argv,"dir=",4)) { + *maildir = x_strdup(4+*argv); + if (*maildir != NULL) { + D(("new mail directory: %s", *maildir)); + ctrl |= PAM_NEW_MAIL_DIR; + } else { + _log_err(LOG_CRIT, + "failed to duplicate mail directory - ignored"); + } + } else if (!strncmp(*argv,"hash=",5)) { + char *ep = NULL; + *hashcount = strtol(*argv+5,&ep,10); + if (!ep || (*hashcount < 0)) { + *hashcount = 0; + } + } else if (!strcmp(*argv,"close")) { + ctrl |= PAM_LOGOUT_TOO; + } else if (!strcmp(*argv,"nopen")) { + ctrl |= PAM_NO_LOGIN; + } else if (!strcmp(*argv,"noenv")) { + ctrl |= PAM_NO_ENV; + } else if (!strcmp(*argv,"empty")) { + ctrl |= PAM_EMPTY_TOO; + } else { + _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + if ((*hashcount != 0) && !(ctrl & PAM_NEW_MAIL_DIR)) { + *maildir = x_strdup(DEFAULT_MAIL_DIRECTORY); + ctrl |= PAM_NEW_MAIL_DIR; + } + + return ctrl; +} + +/* a front end for conversations */ + +static int converse(pam_handle_t *pamh, int ctrl, int nargs + , struct pam_message **message + , struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse")); + + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS ) { + + retval = conv->conv(nargs, ( const struct pam_message ** ) message + , response, conv->appdata_ptr); + + D(("returned from application's conversation function")); + + if (retval != PAM_SUCCESS && (PAM_DEBUG_ARG & ctrl) ) { + _log_err(LOG_DEBUG, "conversation failure [%s]" + , pam_strerror(pamh, retval)); + } + + } else { + _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" + , pam_strerror(pamh, retval)); + } + + D(("ready to return from module conversation")); + + return retval; /* propagate error status */ +} + +static int get_folder(pam_handle_t *pamh, int ctrl, + char **path_mail, char **folder_p, int hashcount) +{ + int retval; + const char *user, *path; + char *folder; + const struct passwd *pwd=NULL; + + retval = pam_get_user(pamh, &user, NULL); + if (retval != PAM_SUCCESS || user == NULL) { + _log_err(LOG_ERR, "no user specified"); + return PAM_USER_UNKNOWN; + } + + if (ctrl & PAM_NEW_MAIL_DIR) { + path = *path_mail; + if (*path == '~') { /* support for $HOME delivery */ + pwd = getpwnam(user); + if (pwd == NULL) { + _log_err(LOG_ERR, "user [%s] unknown", user); + _pam_overwrite(*path_mail); + _pam_drop(*path_mail); + return PAM_USER_UNKNOWN; + } + /* + * "~/xxx" and "~xxx" are treated as same + */ + if (!*++path || (*path == '/' && !*++path)) { + _log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail); + _pam_overwrite(*path_mail); + _pam_drop(*path_mail); + return PAM_ABORT; + } + ctrl |= PAM_HOME_MAIL; + if (hashcount != 0) { + _log_err(LOG_ALERT, "can't do hash= and home directory mail"); + } + } + } else { + path = DEFAULT_MAIL_DIRECTORY; + } + + /* put folder together */ + + if (ctrl & PAM_HOME_MAIL) { + folder = malloc(sizeof(MAIL_FILE_FORMAT) + +strlen(pwd->pw_dir)+strlen(path)); + } else { + folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user) + +2*hashcount); + } + + if (folder != NULL) { + if (ctrl & PAM_HOME_MAIL) { + sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path); + } else { + int i; + char *hash = malloc(2*hashcount+1); + + if (hash) { + for (i = 0; i < hashcount; i++) { + hash[2*i] = '/'; + hash[2*i+1] = user[i]; + } + hash[2*i] = '\0'; + sprintf(folder, MAIL_FILE_FORMAT, path, hash, user); + _pam_overwrite(hash); + _pam_drop(hash); + } else { + sprintf(folder, "error"); + } + } + D(("folder =[%s]", folder)); + } + + /* tidy up */ + + _pam_overwrite(*path_mail); + _pam_drop(*path_mail); + user = NULL; + + if (folder == NULL) { + _log_err(LOG_CRIT, "out of memory for mail folder"); + return PAM_BUF_ERR; + } + + *folder_p = folder; + folder = NULL; + + return PAM_SUCCESS; +} + +static const char *get_mail_status(int ctrl, const char *folder) +{ + const char *type = NULL; + static char dir[256]; + struct stat mail_st; + struct dirent **namelist; + int i; + + if (stat(folder, &mail_st) == 0) { + if (S_ISDIR(mail_st.st_mode)) { /* Assume Maildir format */ + sprintf(dir, "%.250s/new", folder); + i = scandir(dir, &namelist, 0, alphasort); + if (i > 2) { + type = "new"; + while (--i) + free(namelist[i]); + } else { + while (--i >= 0) + free(namelist[i]); + sprintf(dir, "%.250s/cur", folder); + i = scandir(dir, &namelist, 0, alphasort); + if (i > 2) { + type = "old"; + while (--i) + free(namelist[i]); + } else if (ctrl & PAM_EMPTY_TOO) { + while (--i >= 0) + free(namelist[i]); + type = "no"; + } else { + type = NULL; + } + } + } else { + if (mail_st.st_size > 0) { + if (mail_st.st_atime < mail_st.st_mtime) /* new */ + type = (ctrl & PAM_STANDARD_MAIL) ? "new " : "new"; + else /* old */ + type = (ctrl & PAM_STANDARD_MAIL) ? "" : "old"; + } else if (ctrl & PAM_EMPTY_TOO) { + type = "no"; + } else { + type = NULL; + } + } + } + + memset(dir, 0, 256); + memset(&mail_st, 0, sizeof(mail_st)); + D(("user has %s mail in %s folder", type, folder)); + return type; +} + +static int report_mail(pam_handle_t *pamh, int ctrl + , const char *type, const char *folder) +{ + int retval; + + if (!(ctrl & PAM_MAIL_SILENT) || ((ctrl & PAM_QUIET_MAIL) && strcmp(type, "new"))) { + char *remark; + + if (ctrl & PAM_STANDARD_MAIL) + if (!strcmp(type, "no")) + remark = malloc(strlen(NO_MAIL_STANDARD_FORMAT)+1); + else + remark = malloc(strlen(YOUR_MAIL_STANDARD_FORMAT)+strlen(type)+1); + else + remark = malloc(strlen(YOUR_MAIL_VERBOSE_FORMAT)+strlen(type)+strlen(folder)+1); + if (remark == NULL) { + retval = PAM_BUF_ERR; + } else { + struct pam_message msg[1], *mesg[1]; + struct pam_response *resp=NULL; + + if (ctrl & PAM_STANDARD_MAIL) + if (!strcmp(type, "no")) + sprintf(remark, NO_MAIL_STANDARD_FORMAT); + else + sprintf(remark, YOUR_MAIL_STANDARD_FORMAT, type); + else + sprintf(remark, YOUR_MAIL_VERBOSE_FORMAT, type, folder); + + mesg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = remark; + + retval = converse(pamh, ctrl, 1, mesg, &resp); + + _pam_overwrite(remark); + _pam_drop(remark); + if (resp) + _pam_drop_reply(resp, 1); + } + } else { + D(("keeping quiet")); + retval = PAM_SUCCESS; + } + + D(("returning %s", pam_strerror(pamh, retval))); + return retval; +} + +static int _do_mail(pam_handle_t *, int, int, const char **, int); + +/* --- authentication functions --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc, + const char **argv) +{ + return PAM_IGNORE; +} + +/* Checking mail as part of authentication */ +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + if (!(flags & (PAM_ESTABLISH_CRED|PAM_DELETE_CRED))) + return PAM_IGNORE; + return _do_mail(pamh,flags,argc,argv,(flags & PAM_ESTABLISH_CRED)); +} + +/* --- session management functions --- */ + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return _do_mail(pamh,flags,argc,argv,0);; +} + +/* Checking mail as part of the session management */ +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return _do_mail(pamh,flags,argc,argv,1); +} + + +/* --- The Beaf (Tm) --- */ + +static int _do_mail(pam_handle_t *pamh, int flags, int argc, + const char **argv, int est) +{ + int retval, ctrl, hashcount; + char *path_mail=NULL, *folder; + const char *type; + + /* + * this module (un)sets the MAIL environment variable, and checks if + * the user has any new mail. + */ + + ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount); + + /* Do we have anything to do? */ + + if (flags & PAM_SILENT) + return PAM_SUCCESS; + + /* which folder? */ + + retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount); + if (retval != PAM_SUCCESS) { + D(("failed to find folder")); + return retval; + } + + /* set the MAIL variable? */ + + if (!(ctrl & PAM_NO_ENV) && est) { + char *tmp; + + tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT)); + if (tmp != NULL) { + sprintf(tmp, MAIL_ENV_FORMAT, folder); + D(("setting env: %s", tmp)); + retval = pam_putenv(pamh, tmp); + _pam_overwrite(tmp); + _pam_drop(tmp); + if (retval != PAM_SUCCESS) { + _pam_overwrite(folder); + _pam_drop(folder); + _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable"); + return retval; + } + } else { + _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable"); + _pam_overwrite(folder); + _pam_drop(folder); + return retval; + } + } else { + D(("not setting " MAIL_ENV_NAME " variable")); + } + + /* + * OK. we've got the mail folder... what about its status? + */ + + if ((est && !(ctrl & PAM_NO_LOGIN)) + || (!est && (ctrl & PAM_LOGOUT_TOO))) { + type = get_mail_status(ctrl, folder); + if (type != NULL) { + retval = report_mail(pamh, ctrl, type, folder); + type = NULL; + } + } + + /* Delete environment variable? */ + if (!est) + (void) pam_putenv(pamh, MAIL_ENV_NAME); + + _pam_overwrite(folder); /* clean up */ + _pam_drop(folder); + + /* indicate success or failure */ + + return retval; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_mail_modstruct = { + "pam_mail", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_mkhomedir/Makefile b/Linux-PAM/modules/pam_mkhomedir/Makefile new file mode 100644 index 00000000..14802d55 --- /dev/null +++ b/Linux-PAM/modules/pam_mkhomedir/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:25 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_mkhomedir + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c b/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c new file mode 100644 index 00000000..9a4640dd --- /dev/null +++ b/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c @@ -0,0 +1,377 @@ +/* PAM Make Home Dir module + + This module will create a users home directory if it does not exist + when the session begins. This allows users to be present in central + database (such as nis, kerb or ldap) without using a distributed + file system or pre-creating a large number of directories. + + Here is a sample /etc/pam.d/login file for Debian GNU/Linux + 2.1: + + auth requisite pam_securetty.so + auth sufficient pam_ldap.so + auth required pam_pwdb.so + auth optional pam_group.so + auth optional pam_mail.so + account requisite pam_time.so + account sufficient pam_ldap.so + account required pam_pwdb.so + session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 + session required pam_pwdb.so + session optional pam_lastlog.so + password required pam_pwdb.so + + Released under the GNU LGPL version 2 or later + Originally written by Jason Gunthorpe <jgg@debian.org> Feb 1999 + Structure taken from pam_lastlogin by Andrew Morgan + <morgan@parc.power.net> 1996 + */ + +/* I want snprintf dammit */ +#define _GNU_SOURCE 1 +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <dirent.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_SESSION + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* argument parsing */ +#define MKHOMEDIR_DEBUG 020 /* keep quiet about things */ +#define MKHOMEDIR_QUIET 040 /* keep quiet about things */ + +static unsigned int UMask = 0022; +static char SkelDir[BUFSIZ] = "/etc/skel"; /* THIS MODULE IS NOT THREAD SAFE */ + +/* some syslogging */ +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-mkhomedir", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static int _pam_parse(int flags, int argc, const char **argv) +{ + int ctrl = 0; + + /* does the appliction require quiet? */ + if ((flags & PAM_SILENT) == PAM_SILENT) + ctrl |= MKHOMEDIR_QUIET; + + /* step through arguments */ + for (; argc-- > 0; ++argv) + { + if (!strcmp(*argv, "silent")) { + ctrl |= MKHOMEDIR_QUIET; + } else if (!strncmp(*argv,"umask=",6)) { + UMask = strtol(*argv+6,0,0); + } else if (!strncmp(*argv,"skel=",5)) { + strncpy(SkelDir,*argv+5,sizeof(SkelDir)); + SkelDir[sizeof(SkelDir)-1] = '\0'; + } else { + _log_err(LOG_ERR, "unknown option; %s", *argv); + } + } + + D(("ctrl = %o", ctrl)); + return ctrl; +} + +/* This common function is used to send a message to the applications + conversion function. Our only use is to ask the application to print + an informative message that we are creating a home directory */ +static int converse(pam_handle_t * pamh, int ctrl, int nargs + ,struct pam_message **message + ,struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse")); + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (retval == PAM_SUCCESS) + { + + retval = conv->conv(nargs, (const struct pam_message **) message + ,response, conv->appdata_ptr); + + D(("returned from application's conversation function")); + + if (retval != PAM_SUCCESS && (ctrl & MKHOMEDIR_DEBUG)) + { + _log_err(LOG_DEBUG, "conversation failure [%s]" + ,pam_strerror(pamh, retval)); + } + + } + else + { + _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" + ,pam_strerror(pamh, retval)); + } + + D(("ready to return from module conversation")); + + return retval; /* propagate error status */ +} + +/* Ask the application to display a short text string for us. */ +static int make_remark(pam_handle_t * pamh, int ctrl, const char *remark) +{ + int retval; + + if ((ctrl & MKHOMEDIR_QUIET) != MKHOMEDIR_QUIET) + { + struct pam_message msg[1], *mesg[1]; + struct pam_response *resp = NULL; + + mesg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = remark; + + retval = converse(pamh, ctrl, 1, mesg, &resp); + + msg[0].msg = NULL; + if (resp) + { + _pam_drop_reply(resp, 1); + } + } + else + { + D(("keeping quiet")); + retval = PAM_SUCCESS; + } + + D(("returning %s", pam_strerror(pamh, retval))); + return retval; +} + +/* Do the actual work of creating a home dir */ +static int create_homedir(pam_handle_t * pamh, int ctrl, + const struct passwd *pwd, + const char *source, const char *dest) +{ + char remark[BUFSIZ]; + DIR *D; + struct dirent *Dir; + + /* Mention what is happening, if the notification fails that is OK */ + if (snprintf(remark,sizeof(remark),"Creating directory '%s'.", dest) == -1) + return PAM_PERM_DENIED; + + make_remark(pamh, ctrl, remark); + + /* Create the new directory */ + if (mkdir(dest,0700) != 0) + { + _log_err(LOG_DEBUG, "unable to create directory %s",source); + return PAM_PERM_DENIED; + } + if (chmod(dest,0777 & (~UMask)) != 0 || + chown(dest,pwd->pw_uid,pwd->pw_gid) != 0) + { + _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest); + return PAM_PERM_DENIED; + } + + /* See if we need to copy the skel dir over. */ + if ((source == NULL) || (strlen(source) == 0)) + { + return PAM_SUCCESS; + } + + /* Scan the directory */ + D = opendir(source); + if (D == 0) + { + _log_err(LOG_DEBUG, "unable to read directory %s",source); + return PAM_PERM_DENIED; + } + + for (Dir = readdir(D); Dir != 0; Dir = readdir(D)) + { + int SrcFd; + int DestFd; + int Res; + struct stat St; + char newsource[PATH_MAX], newdest[PATH_MAX]; + + /* Skip some files.. */ + if (strcmp(Dir->d_name,".") == 0 || + strcmp(Dir->d_name,"..") == 0) + continue; + + /* Determine what kind of file it is. */ + snprintf(newsource,sizeof(newsource),"%s/%s",source,Dir->d_name); + if (lstat(newsource,&St) != 0) + continue; + + /* We'll need the new file's name. */ + snprintf(newdest,sizeof(newdest),"%s/%s",dest,Dir->d_name); + + /* If it's a directory, recurse. */ + if (S_ISDIR(St.st_mode)) + { + create_homedir(pamh, ctrl, pwd, newsource, newdest); + continue; + } + + /* If it's a symlink, create a new link. */ + if (S_ISLNK(St.st_mode)) + { + char pointed[PATH_MAX]; + memset(pointed, 0, sizeof(pointed)); + if(readlink(newsource, pointed, sizeof(pointed) - 1) != -1) + { + if(symlink(pointed, newdest) == 0) + { + if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0) + { + _log_err(LOG_DEBUG, "unable to chang perms on link %s", + newdest); + return PAM_PERM_DENIED; + } + } + } + continue; + } + + /* If it's not a regular file, it's probably not a good idea to create + * the new device node, FIFO, or whatever it is. */ + if (!S_ISREG(St.st_mode)) + { + continue; + } + + /* Open the source file */ + if ((SrcFd = open(newsource,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) + { + _log_err(LOG_DEBUG, "unable to open src file %s",newsource); + return PAM_PERM_DENIED; + } + stat(newsource,&St); + + /* Open the dest file */ + if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) + { + close(SrcFd); + _log_err(LOG_DEBUG, "unable to open dest file %s",newdest); + return PAM_PERM_DENIED; + } + + /* Set the proper ownership and permissions for the module. We make + the file a+w and then mask it with the set mask. This preseves + execute bits */ + if (fchmod(DestFd,(St.st_mode | 0222) & (~UMask)) != 0 || + fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0) + { + close(SrcFd); + close(DestFd); + _log_err(LOG_DEBUG, "unable to chang perms on copy %s",newdest); + return PAM_PERM_DENIED; + } + + /* Copy the file */ + do + { + Res = read(SrcFd,remark,sizeof(remark)); + if (Res < 0 || write(DestFd,remark,Res) != Res) + { + close(SrcFd); + close(DestFd); + _log_err(LOG_DEBUG, "unable to perform IO"); + return PAM_PERM_DENIED; + } + } + while (Res != 0); + close(SrcFd); + close(DestFd); + } + + return PAM_SUCCESS; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc + ,const char **argv) +{ + int retval, ctrl; + const char *user; + const struct passwd *pwd; + struct stat St; + + /* Parse the flag values */ + ctrl = _pam_parse(flags, argc, argv); + + /* Determine the user name so we can get the home directory */ + retval = pam_get_item(pamh, PAM_USER, (const void **) &user); + if (retval != PAM_SUCCESS || user == NULL || *user == '\0') + { + _log_err(LOG_NOTICE, "user unknown"); + return PAM_USER_UNKNOWN; + } + + /* Get the password entry */ + pwd = getpwnam(user); + if (pwd == NULL) + { + D(("couldn't identify user %s", user)); + return PAM_CRED_INSUFFICIENT; + } + + /* Stat the home directory, if something exists then we assume it is + correct and return a success*/ + if (stat(pwd->pw_dir,&St) == 0) + return PAM_SUCCESS; + + return create_homedir(pamh,ctrl,pwd,SkelDir,pwd->pw_dir); +} + +/* Ignore */ +PAM_EXTERN +int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ +struct pam_module _pam_mkhomedir_modstruct = +{ + "pam_mkhomedir", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif diff --git a/Linux-PAM/modules/pam_motd/Makefile b/Linux-PAM/modules/pam_motd/Makefile new file mode 100644 index 00000000..ad6a2497 --- /dev/null +++ b/Linux-PAM/modules/pam_motd/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_motd + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_motd/pam_motd.c b/Linux-PAM/modules/pam_motd/pam_motd.c new file mode 100644 index 00000000..931dfd10 --- /dev/null +++ b/Linux-PAM/modules/pam_motd/pam_motd.c @@ -0,0 +1,123 @@ +/* pam_motd module */ + +/* + * Modified for pam_motd by Ben Collins <bcollins@debian.org> + * + * Based off of: + * $Id: pam_motd.c,v 1.1.1.2 2002/09/15 20:08:52 hartmans Exp $ + * + * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 + * + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> + +#include <security/_pam_macros.h> +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_SESSION +#define DEFAULT_MOTD "/etc/motd" + +#include <security/pam_modules.h> + +/* --- session management functions (only) --- */ + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return PAM_IGNORE; +} + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int retval = PAM_IGNORE; + int fd; + char *mtmp=NULL; + const char *motd_path=NULL; + struct pam_conv *conversation; + struct pam_message message; + struct pam_message *pmessage = &message; + struct pam_response *resp = NULL; + struct stat st; + + if (flags & PAM_SILENT) { + return retval; + } + + for (; argc-- > 0; ++argv) { + if (!strncmp(*argv,"motd=",5)) { + + motd_path = (char *) strdup(5+*argv); + if (motd_path != NULL) { + D(("set motd path: %s (and a memory leak)", motd_path)); + } else { + D(("failed to duplicate motd path - ignored")); + } + } + } + + if (motd_path == NULL) + motd_path = DEFAULT_MOTD; + + message.msg_style = PAM_TEXT_INFO; + + if ((fd = open(motd_path, O_RDONLY, 0)) >= 0) { + /* fill in message buffer with contents of motd */ + if ((fstat(fd, &st) < 0) || !st.st_size) + return retval; + message.msg = mtmp = malloc(st.st_size+1); + /* if malloc failed... */ + if (!message.msg) return retval; + read(fd, mtmp, st.st_size); + if (mtmp[st.st_size-1] == '\n') + mtmp[st.st_size-1] = '\0'; + else + mtmp[st.st_size] = '\0'; + close(fd); + /* Use conversation function to give user contents of motd */ + pam_get_item(pamh, PAM_CONV, (const void **)&conversation); + conversation->conv(1, (const struct pam_message **)&pmessage, + &resp, conversation->appdata_ptr); + free(mtmp); + if (resp) + _pam_drop_reply(resp, 1); + } + + return retval; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_motd_modstruct = { + "pam_motd", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_nologin/Makefile b/Linux-PAM/modules/pam_nologin/Makefile new file mode 100644 index 00000000..494d2909 --- /dev/null +++ b/Linux-PAM/modules/pam_nologin/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_nologin + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_nologin/README b/Linux-PAM/modules/pam_nologin/README new file mode 100644 index 00000000..5f7d6ced --- /dev/null +++ b/Linux-PAM/modules/pam_nologin/README @@ -0,0 +1,23 @@ +# $Id: README,v 1.1.1.2 2002/09/15 20:08:52 hartmans Exp $ +# + +This module always lets root in; it lets other users in only if the file +/etc/nologin doesn't exist. In any case, if /etc/nologin exists, it's +contents are displayed to the user. + +The default return value for this module is PAM_IGNORE, you can +override this with the successok module argument. + +module services provided: + + auth _authenticate and _setcred + account _acct_mgmt + +optional arguments: + + file=<alternative-nologin-pathname> - choose a different file + successok - return PAM_SUCCESS if no file + +[Original README by Michael K. Johnson] + + diff --git a/Linux-PAM/modules/pam_nologin/pam_nologin.c b/Linux-PAM/modules/pam_nologin/pam_nologin.c new file mode 100644 index 00000000..ea5d86e9 --- /dev/null +++ b/Linux-PAM/modules/pam_nologin/pam_nologin.c @@ -0,0 +1,197 @@ +/* pam_nologin module */ + +/* + * $Id: pam_nologin.c,v 1.1.1.2 2002/09/15 20:08:53 hartmans Exp $ + * + * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> + +#include <security/_pam_macros.h> +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +#include <security/_pam_modutil.h> + +/* + * parse some command line options + */ +struct opt_s { + int retval_when_nofile; + const char *nologin_file; +}; + +static void parse_args(pam_handle_t *pamh, int argc, const char **argv, + struct opt_s *opts) +{ + int i; + + memset(opts, 0, sizeof(*opts)); + + opts->retval_when_nofile = PAM_IGNORE; + opts->nologin_file = "/etc/nologin"; + + for (i=0; i<argc; ++i) { + if (!strcmp("successok", argv[i])) { + opts->retval_when_nofile = PAM_SUCCESS; + } else if (!memcmp("file=", argv[i], 5)) { + opts->nologin_file = argv[i] + 5; + } else { + /* XXX - ignore for now. Later, we'll use the logging + function in pammodutils */ + } + } +} + +/* + * do the meat of the work for this module + */ + +static int perform_check(pam_handle_t *pamh, struct opt_s *opts) +{ + const char *username; + int retval = PAM_SUCCESS; + int fd; + + retval = opts->retval_when_nofile; + + if ((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username) { + return PAM_USER_UNKNOWN; + } + + if ((fd = open(opts->nologin_file, O_RDONLY, 0)) >= 0) { + + char *mtmp=NULL; + struct passwd *user_pwd; + struct pam_conv *conversation; + struct pam_message message; + struct pam_message *pmessage = &message; + struct pam_response *resp = NULL; + struct stat st; + + user_pwd = _pammodutil_getpwnam(pamh, username); + if (user_pwd == NULL) { + + retval = PAM_USER_UNKNOWN; + message.msg_style = PAM_ERROR_MSG; + + } else if (user_pwd->pw_uid) { + + retval = PAM_AUTH_ERR; + message.msg_style = PAM_ERROR_MSG; + + } else { + + /* root can still log in; lusers cannot */ + message.msg_style = PAM_TEXT_INFO; + + } + + /* fill in message buffer with contents of /etc/nologin */ + if (fstat(fd, &st) < 0) { + /* give up trying to display message */ + goto clean_up_fd; + } + + message.msg = mtmp = malloc(st.st_size+1); + if (!message.msg) { + /* if malloc failed... */ + retval = PAM_BUF_ERR; + goto clean_up_fd; + } + + read(fd, mtmp, st.st_size); + mtmp[st.st_size] = '\000'; + + /* + * Use conversation function to give user contents of /etc/nologin + */ + + pam_get_item(pamh, PAM_CONV, (const void **)&conversation); + (void) conversation->conv(1, (const struct pam_message **)&pmessage, + &resp, conversation->appdata_ptr); + free(mtmp); + + if (resp) { + _pam_drop_reply(resp, 1); + } + + clean_up_fd: + + close(fd); + } + + return retval; +} + +/* --- authentication management functions --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + struct opt_s opts; + + parse_args(pamh, argc, argv, &opts); + + return perform_check(pamh, &opts); +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + struct opt_s opts; + + parse_args(pamh, argc, argv, &opts); + + return opts.retval_when_nofile; +} + +/* --- account management function --- */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + struct opt_s opts; + + parse_args(pamh, argc, argv, &opts); + + return perform_check(pamh, &opts); +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_nologin_modstruct = { + "pam_nologin", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_permit/Makefile b/Linux-PAM/modules/pam_permit/Makefile new file mode 100644 index 00000000..23835be4 --- /dev/null +++ b/Linux-PAM/modules/pam_permit/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_permit + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_permit/README b/Linux-PAM/modules/pam_permit/README new file mode 100644 index 00000000..15d95942 --- /dev/null +++ b/Linux-PAM/modules/pam_permit/README @@ -0,0 +1,4 @@ +# $Id: README,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# + +this module always returns PAM_SUCCESS, it ignores all options. diff --git a/Linux-PAM/modules/pam_permit/pam_permit.c b/Linux-PAM/modules/pam_permit/pam_permit.c new file mode 100644 index 00000000..1041ca84 --- /dev/null +++ b/Linux-PAM/modules/pam_permit/pam_permit.c @@ -0,0 +1,112 @@ +/* pam_permit module */ + +/* + * $Id: pam_permit.c,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 + * + */ + +#define DEFAULT_USER "nobody" + +#include <stdio.h> + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +/* --- authentication management functions --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int retval; + const char *user=NULL; + + /* + * authentication requires we know who the user wants to be + */ + retval = pam_get_user(pamh, &user, NULL); + if (retval != PAM_SUCCESS) { + D(("get user returned error: %s", pam_strerror(pamh,retval))); + return retval; + } + if (user == NULL || *user == '\0') { + D(("username not known")); + pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + } + user = NULL; /* clean up */ + + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +/* --- account management functions --- */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +/* --- password management --- */ + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +/* --- session management --- */ + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + +/* end of module definition */ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_permit_modstruct = { + "pam_permit", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; + +#endif diff --git a/Linux-PAM/modules/pam_pwdb/BUGS b/Linux-PAM/modules/pam_pwdb/BUGS new file mode 100644 index 00000000..7258822c --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/BUGS @@ -0,0 +1,3 @@ +$Id: BUGS,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ + +As of Linux-PAM-0.52 this is new. No known bugs yet. diff --git a/Linux-PAM/modules/pam_pwdb/CHANGELOG b/Linux-PAM/modules/pam_pwdb/CHANGELOG new file mode 100644 index 00000000..78c1a239 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/CHANGELOG @@ -0,0 +1,10 @@ +$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ + +Tue Apr 23 12:28:09 EDT 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu) + + * PAM_DISALLOW_NULL_AUTHTOK implemented in the authentication module + * pam_sm_open_session() and pam_sm_close_session() implemented + A new "trace" flag added to flags of /etc/pam.conf. Using this + flag system administrator is able to make pam_unix module provide + very extensive audit trail sent so syslog with LOG_AUTHPRIV level. + * pam_sm_set_cred() is done diff --git a/Linux-PAM/modules/pam_pwdb/Makefile b/Linux-PAM/modules/pam_pwdb/Makefile new file mode 100644 index 00000000..bce2950f --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/Makefile @@ -0,0 +1,124 @@ +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +# +# This Makefile controls a build process of the pam_unix module +# for Linux-PAM. You should not modify this Makefile. +# +# rewritten to compile new module Andrew Morgan +# <morgan@parc.power.net> 1996/11/6 +# + +include ../../Make.Rules + +ifeq ($(HAVE_LIBPWDB),yes) + +EXTRALS += -lpwdb +EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" + +ifeq ($(HAVE_LIBCRYPT),yes) + EXTRALS += -lcrypt +endif + +TITLE=pam_pwdb +CHKPWD=pwdb_chkpwd + +LIBSRC = $(TITLE).c +LIBOBJ = $(TITLE).o +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +#LIBOBJS = $(addprefix static/,$(LIBOBJ)) +LIBDEPS = pam_unix_acct.-c pam_unix_auth.-c pam_unix_passwd.-c \ + pam_unix_sess.-c pam_unix_pwupd.-c support.-c bigcrypt.-c + +PLUS += md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o +CFLAGS += $(EXTRAS) + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif +#ifdef STATIC +#LIBSTATIC = lib$(TITLE).o +#endif + +all: info dirs $(PLUS) $(LIBSHARED) $(LIBSTATIC) register $(CHKPWD) + +dynamic/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS) + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +#static/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS) +# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +info: + @echo + @echo "*** Building PAM_pwdb module..." + @echo + +$(CHKPWD): pwdb_chkpwd.o md5_good.o md5_broken.o \ + md5_crypt_good.o md5_crypt_broken.o + $(CC) -o $(CHKPWD) $^ -lpwdb + +pwdb_chkpwd.o: pwdb_chkpwd.c pam_unix_md.-c bigcrypt.-c + +md5_good.o: md5.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_broken.o: md5.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_crypt_good.o: md5_crypt.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_crypt_broken.o: md5_crypt.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ + $(TARGET_ARCH) -c $< -o $@ + +dirs: +ifdef DYNAMIC + @$(MKDIR) ./dynamic +endif +#ifdef STATIC +# @$(MKDIR) ./static +#endif + +register: +#ifdef STATIC +# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +#endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(EXTRALS) +endif + +#ifdef STATIC +#$(LIBOBJS): $(LIBSRC) +# +#$(LIBSTATIC): $(LIBOBJS) +# $(LD) -r -o $@ $(LIBOBJS) $(PLUS) $(EXTRALS) +#endif + +install: all + $(MKDIR) $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) + $(INSTALL) -m 4555 $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED) + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) + +clean: + rm -f $(CHKPWD) $(LIBOBJD) $(LIBOBJS) $(MOREDELS) core *~ *.o *.so + rm -f *.a *.o *.so *.bak + rm -fr dynamic static + +else + +include ../dont_makefile + +endif diff --git a/Linux-PAM/modules/pam_pwdb/README b/Linux-PAM/modules/pam_pwdb/README new file mode 100644 index 00000000..4f420855 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/README @@ -0,0 +1,41 @@ +This is the pam_unix module. It has been significantly rewritten since +.51 was released (due mostly to the efforts of Cristian Gafton), and +now takes more options and correctly updates vanilla UNIX/shadow/md5 +passwords. + +[Please read the source and make a note of all the warnings there, as +the license suggests -- use at your own risk.] + +So far as I am concerned this module is now pretty stable. If you find +any bugs, PLEASE tell me! <morgan@linux.kernel.org> + +Options recognized by this module are as follows: + + debug - log more debugging info + audit - a little more extreme than debug + use_first_pass - don't prompt the user for passwords + take them from PAM_ items instead + try_first_pass - don't prompt the user for the passwords + unless PAM_(OLD)AUTHTOK is unset + use_authtok - like try_first_pass, but *fail* if the new + PAM_AUTHTOK has not been previously set. + (intended for stacking password modules only) + not_set_pass - don't set the PAM_ items with the passwords + used by this module. + shadow - try to maintian a shadow based system. + unix - when changing passwords, they are placed + in the /etc/passwd file + md5 - when a user changes their password next, + encrypt it with the md5 algorithm. + bigcrypt - when a user changes their password next, + excrypt it with the DEC C2-algorithm(0). + nodelay - used to prevent failed authentication + resulting in a delay of about 1 second. + +There is some support for building a shadow file on-the-fly from an +/etc/passwd file. This is VERY alpha. If you want to play with it you +should read the source to find the appropriate #define that you will +need. + +--------------------- +Andrew Morgan <morgan@linux.kernel.org> diff --git a/Linux-PAM/modules/pam_pwdb/TODO b/Linux-PAM/modules/pam_pwdb/TODO new file mode 100644 index 00000000..04635859 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/TODO @@ -0,0 +1,34 @@ +$Id: TODO,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ + + * get NIS working + * .. including "nonis" argument + * add helper binary + +Wed Sep 4 23:40:09 PDT 1996 Andrew G. Morgan + + * verify that it works for everyone + * look more seriously at the issue of generating a shadow + system on the fly + * add some more password flavors + +Thu Aug 29 06:26:42 PDT 1996 Andrew G. Morgan + + * check that complete rewrite works! ;^) + * complete shadow support to the password changing code. + Also some code needed here for session managment? + (both pam.conf argument to turn it on/off, and some + conditional compilation.) + * md5 passwords... + * make the exclusive nature of the arguments work. That is, + only recognize the flags when appropriate. + +Wed May 8 19:08:49 EDT 1996 Alexander O. Yuriev + + * support.c should go. + +Tue Apr 23 21:43:55 EDT 1996 Alexander O. Yuriev + + * pam_sm_chauth_tok() should be written + * QUICK FIX: pam_sm_setcred() probably returns incorrect error code + + diff --git a/Linux-PAM/modules/pam_pwdb/bigcrypt.-c b/Linux-PAM/modules/pam_pwdb/bigcrypt.-c new file mode 100644 index 00000000..321f2491 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/bigcrypt.-c @@ -0,0 +1,114 @@ +/* + * This function implements the "bigcrypt" algorithm specifically for + * Linux-PAM. + * + * This algorithm is algorithm 0 (default) shipped with the C2 secure + * implementation of Digital UNIX. + * + * Disclaimer: This work is not based on the source code to Digital + * UNIX, nor am I connected to Digital Equipment Corp, in any way + * other than as a customer. This code is based on published + * interfaces and reasonable guesswork. + * + * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8 + * characters or less. Each block is encrypted using the standard UNIX + * libc crypt function. The result of the encryption for one block + * provides the salt for the suceeding block. + * + * Restrictions: The buffer used to hold the encrypted result is + * statically allocated. (see MAX_PASS_LEN below). This is necessary, + * as the returned pointer points to "static data that are overwritten + * by each call", (XPG3: XSI System Interface + Headers pg 109), and + * this is a drop in replacement for crypt(); + * + * Andy Phillips <atp@mssl.ucl.ac.uk> + */ + +/* + * Max cleartext password length in segments of 8 characters this + * function can deal with (16 segments of 8 chars= max 128 character + * password). + */ + +#define MAX_PASS_LEN 16 +#define SEGMENT_SIZE 8 +#define SALT_SIZE 2 +#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE) +#define ESEGMENT_SIZE 11 +#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1) + +static char *bigcrypt(const char *key, const char *salt) +{ + static char dec_c2_cryptbuf[CBUF_SIZE]; /* static storage area */ + + unsigned long int keylen,n_seg,j; + char *cipher_ptr,*plaintext_ptr,*tmp_ptr,*salt_ptr; + char keybuf[KEYBUF_SIZE+1]; + + D(("called with key='%s', salt='%s'.", key, salt)); + + /* reset arrays */ + memset(keybuf, 0, KEYBUF_SIZE+1); + memset(dec_c2_cryptbuf, 0, CBUF_SIZE); + + /* fill KEYBUF_SIZE with key */ + strncpy(keybuf, key, KEYBUF_SIZE); + + /* deal with case that we are doing a password check for a + conventially encrypted password: the salt will be + SALT_SIZE+ESEGMENT_SIZE long. */ + if (strlen(salt) == (SALT_SIZE+ESEGMENT_SIZE)) + keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */ + + keylen = strlen(keybuf); + + if (!keylen) { + n_seg = 1; + } else { + /* work out how many segments */ + n_seg = 1 + ((keylen-1)/SEGMENT_SIZE); + } + + if (n_seg > MAX_PASS_LEN) + n_seg = MAX_PASS_LEN; /* truncate at max length */ + + /* set up some pointers */ + cipher_ptr = dec_c2_cryptbuf; + plaintext_ptr = keybuf; + + /* do the first block with supplied salt */ + tmp_ptr = crypt(plaintext_ptr,salt); /* libc crypt() */ + + /* and place in the static area */ + strncpy(cipher_ptr, tmp_ptr, 13); + cipher_ptr += ESEGMENT_SIZE + SALT_SIZE; + plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */ + + /* change the salt (1st 2 chars of previous block) - this was found + by dowsing */ + + salt_ptr = cipher_ptr - ESEGMENT_SIZE; + + /* so far this is identical to "return crypt(key, salt);", if + there is more than one block encrypt them... */ + + if (n_seg > 1) { + for (j=2; j <= n_seg; j++) { + + tmp_ptr = crypt(plaintext_ptr, salt_ptr); + + /* skip the salt for seg!=0 */ + strncpy(cipher_ptr, (tmp_ptr+SALT_SIZE), ESEGMENT_SIZE); + + cipher_ptr += ESEGMENT_SIZE; + plaintext_ptr += SEGMENT_SIZE; + salt_ptr = cipher_ptr - ESEGMENT_SIZE; + } + } + + D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf)); + + /* this is the <NUL> terminated encrypted password */ + + return dec_c2_cryptbuf; +} diff --git a/Linux-PAM/modules/pam_pwdb/md5.c b/Linux-PAM/modules/pam_pwdb/md5.c new file mode 100644 index 00000000..a0e5a974 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/md5.c @@ -0,0 +1,255 @@ +/* $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ + * + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + */ + +#include <string.h> +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +static void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Name(MD5Init)(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301U; + ctx->buf[1] = 0xefcdab89U; + ctx->buf[2] = 0x98badcfeU; + ctx->buf[3] = 0x10325476U; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/Linux-PAM/modules/pam_pwdb/md5.h b/Linux-PAM/modules/pam_pwdb/md5.h new file mode 100644 index 00000000..75c4dbac --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/md5.h @@ -0,0 +1,30 @@ +#ifndef MD5_H +#define MD5_H + +typedef unsigned int uint32; + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +void GoodMD5Init(struct MD5Context *); +void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned); +void GoodMD5Final(unsigned char digest[16], struct MD5Context *); +void GoodMD5Transform(uint32 buf[4], uint32 const in[16]); +void BrokenMD5Init(struct MD5Context *); +void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned); +void BrokenMD5Final(unsigned char digest[16], struct MD5Context *); +void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]); + +char *Goodcrypt_md5(const char *pw, const char *salt); +char *Brokencrypt_md5(const char *pw, const char *salt); + +/* +* This is needed to make RSAREF happy on some MS-DOS compilers. +*/ + +typedef struct MD5Context MD5_CTX; + +#endif /* MD5_H */ diff --git a/Linux-PAM/modules/pam_pwdb/md5_crypt.c b/Linux-PAM/modules/pam_pwdb/md5_crypt.c new file mode 100644 index 00000000..28f22727 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/md5_crypt.c @@ -0,0 +1,138 @@ +/* $Id: md5_crypt.c,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp + * + */ + +#include <string.h> +#include "md5.h" + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void +to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ + +char * MD5Name(crypt_md5)(const char *pw, const char *salt) +{ + const char *magic = "$1$"; + /* This string is magic for this algorithm. Having + * it this way, we can get get better later on */ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[16]; + int sl,pl,i,j; + MD5_CTX ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Name(MD5Init)(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw)); + + /* Then our magic string */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic)); + + /* Then the raw salt */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + MD5Name(MD5Init)(&ctx1); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Final)(final,&ctx1); + for(pl = strlen(pw); pl > 0; pl -= 16) + MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + /* Then something really weird... */ + for (j=0,i = strlen(pw); i ; i >>= 1) + if(i&1) + MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1); + else + MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + MD5Name(MD5Final)(final,&ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for(i=0;i<1000;i++) { + MD5Name(MD5Init)(&ctx1); + if(i & 1) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + else + MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); + + if(i % 3) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); + + if(i % 7) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + + if(i & 1) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); + else + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Final)(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; + l = final[11] ; to64(p,l,2); p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + return passwd; +} + diff --git a/Linux-PAM/modules/pam_pwdb/pam_pwdb.c b/Linux-PAM/modules/pam_pwdb/pam_pwdb.c new file mode 100644 index 00000000..c2a5639c --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_pwdb.c @@ -0,0 +1,248 @@ +/* + * $Id: pam_pwdb.c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * + * This is the single file that will be compiled for pam_unix. + * it includes each of the modules that have beed defined in the .-c + * files in this directory. + * + * It is a little ugly to do it this way, but it is a simple way of + * defining static functions only once, and yet keeping the separate + * files modular. If you can think of something better, please email + * Andrew Morgan <morgan@linux.kernel.org> + * + * See the end of this file for Copyright information. + */ + +static const char rcsid[] = +"$Id: pam_pwdb.c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $\n" +" - PWDB Pluggable Authentication module. <morgan@linux.kernel.org>" +; + +/* #define DEBUG */ + +#include <security/_pam_aconf.h> + +#include <sys/types.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> +#include <time.h> /* for time() */ +#include <fcntl.h> +#include <ctype.h> + +#include <sys/time.h> +#include <unistd.h> + +#include <pwdb/pwdb_public.h> + +/* indicate the following groups are defined */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +#include "./support.-c" + +/* + * PAM framework looks for these entry-points to pass control to the + * authentication module. + */ + +#include "./pam_unix_auth.-c" + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_auth( pamh, ctrl ); + pwdb_end(); + + if ( on(UNIX_LIKE_AUTH, ctrl) ) { + D(("recording return code for next time [%d]", retval)); + pam_set_data(pamh, "pwdb_setcred_return", (void *) retval, NULL); + } + + D(("done. [%s]", pam_strerror(pamh, retval))); + + return retval; +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags + , int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_set_credentials(pamh, ctrl); + pwdb_end(); + + if ( on(UNIX_LIKE_AUTH, ctrl) ) { + int *pretval = &retval; + + D(("recovering return code from auth call")); + pam_get_data(pamh, "pwdb_setcred_return", (const void **) pretval); + D(("recovered data indicates that old retval was %d", retval)); + } + + return retval; +} + +/* + * PAM framework looks for these entry-points to pass control to the + * account management module. + */ + +#include "./pam_unix_acct.-c" + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_acct_mgmt(pamh, ctrl); + pwdb_end(); + + D(("done.")); + + return retval; +} + +/* + * PAM framework looks for these entry-points to pass control to the + * session module. + */ + +#include "./pam_unix_sess.-c" + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_open_session(pamh, ctrl); + pwdb_end(); + + return retval; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_close_session(pamh, ctrl); + pwdb_end(); + + return retval; +} + +/* + * PAM framework looks for these entry-points to pass control to the + * password changing module. + */ + +#include "./pam_unix_passwd.-c" + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + int retval; + + D(("called.")); + + pwdb_start(); + ctrl = set_ctrl(flags, argc, argv); + retval = _unix_chauthtok(pamh, ctrl); + pwdb_end(); + + D(("done.")); + + return retval; +} + +/* static module data */ + +#ifdef PAM_STATIC +struct pam_module _pam_pwdb_modstruct = { + "pam_pwdb", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; + +#endif + +/* + * Copyright (c) Andrew G. Morgan, 1996. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c new file mode 100644 index 00000000..3a6ff1ed --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c @@ -0,0 +1,272 @@ +/* + * $Id: pam_unix_acct.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * + * See end of file for copyright information + */ + +static const char rcsid_acct[] = +"$Id: pam_unix_acct.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $\n" +" - PAM_PWDB account management <gafton@redhat.com>"; + +/* the shadow suite has accout managment.. */ + +static int _shadow_acct_mgmt_exp(pam_handle_t *pamh, unsigned int ctrl, + const struct pwdb *pw, const char *uname) +{ + const struct pwdb_entry *pwe = NULL; + time_t curdays; + int last_change, max_change; + int retval; + + D(("called.")); + + /* Now start the checks */ + + curdays = time(NULL)/(60*60*24); /* today */ + + /* First: has account expired ? (CG) + * - expire < curdays + * - or (last_change + max_change + defer_change) < curdays + * - in both cases, deny access + */ + + D(("pwdb_get_entry")); + retval = pwdb_get_entry(pw, "expire", &pwe); + if (retval == PWDB_SUCCESS) { + int expire; + + expire = *( (const int *) pwe->value ); + (void) pwdb_entry_delete(&pwe); /* no longer needed */ + + if ((curdays > expire) && (expire > 0)) { + + _log_err(LOG_NOTICE + , "acct: account %s has expired (account expired)" + , uname); + make_remark(pamh, ctrl, PAM_ERROR_MSG + , "Your account has expired; " + "please contact your system administrator"); + + D(("account expired")); + return PAM_ACCT_EXPIRED; + } + } + + D(("pwdb_get_entry")); + retval = pwdb_get_entry(pw, "last_change", &pwe); + if ( retval == PWDB_SUCCESS ) { + last_change = *( (const int *) pwe->value ); + } else { + last_change = curdays; + } + (void) pwdb_entry_delete(&pwe); + + D(("pwdb_get_entry")); + retval = pwdb_get_entry(pw, "max_change", &pwe); + if ( retval == PWDB_SUCCESS ) { + max_change = *( (const int *) pwe->value ); + } else { + max_change = -1; + } + (void) pwdb_entry_delete(&pwe); + + D(("pwdb_get_entry")); + retval = pwdb_get_entry(pw, "defer_change", &pwe); + if (retval == PWDB_SUCCESS) { + int defer_change; + + defer_change = *( (const int *) pwe->value ); + (void) pwdb_entry_delete(&pwe); + + if ((curdays > (last_change + max_change + defer_change)) + && (max_change != -1) && (defer_change != -1) + && (last_change > 0)) { + + if ( on(UNIX_DEBUG, ctrl) ) { + _log_err(LOG_NOTICE, "acct: account %s has expired " + "(failed to change password)", uname); + } + make_remark(pamh, ctrl, PAM_ERROR_MSG + , "Your password has expired; " + "please see your system administrator"); + + D(("account expired2")); + return PAM_ACCT_EXPIRED; + } + } + + /* Now test if the password is expired, but the user still can + * change their password. (CG) + * - last_change = 0 + * - last_change + max_change < curdays + */ + + D(("when was the last change")); + if (last_change == 0) { + + if ( on(UNIX_DEBUG, ctrl) ) { + _log_err(LOG_NOTICE + , "acct: expired password for user %s (root enforced)" + , uname); + } + make_remark(pamh, ctrl, PAM_ERROR_MSG + , "You are required to change your password immediately" + ); + + D(("need a new password")); + return PAM_NEW_AUTHTOK_REQD; + } + + if (((last_change + max_change) < curdays) && + (max_change < 99999) && (max_change > 0)) { + + if ( on(UNIX_DEBUG, ctrl) ) { + _log_err(LOG_DEBUG + , "acct: expired password for user %s (password aged)" + , uname); + } + make_remark(pamh, ctrl, PAM_ERROR_MSG + , "Your password has expired; please change it!"); + + D(("need a new password 2")); + return PAM_NEW_AUTHTOK_REQD; + } + + /* + * Now test if the password is about to expire (CG) + * - last_change + max_change - curdays <= warn_change + */ + + retval = pwdb_get_entry(pw, "warn_change", &pwe); + if ( retval == PWDB_SUCCESS ) { + int warn_days, daysleft; + + daysleft = last_change + max_change - curdays; + warn_days = *((const int *) pwe->value); + (void) pwdb_entry_delete(&pwe); + + if ((daysleft <= warn_days) && (warn_days > 0)) { + char *s; + + if ( on(UNIX_DEBUG, ctrl) ) { + _log_err(LOG_DEBUG + , "acct: password for user %s will expire in %d days" + , uname, daysleft); + } + +#define LocalComment "Warning: your password will expire in %d day%s" + if ((s = (char *) malloc(30+sizeof(LocalComment))) == NULL) { + _log_err(LOG_CRIT, "malloc failure in " __FILE__); + retval = PAM_BUF_ERR; + } else { + + sprintf(s, LocalComment, daysleft, daysleft == 1 ? "":"s"); + + make_remark(pamh, ctrl, PAM_TEXT_INFO, s); + free(s); + } +#undef LocalComment + } + } else { + retval = PAM_SUCCESS; + } + + D(("all done")); + return retval; +} + + +/* + * this function checks for the account details. The user may not be + * permitted to log in at this time etc.. Within the context of + * vanilla Unix, this function simply does nothing. The shadow suite + * added password/account expiry, but PWDB takes care of this + * transparently. + */ + +static int _unix_acct_mgmt(pam_handle_t *pamh, unsigned int ctrl) +{ + const struct pwdb *pw = NULL; + + char *uname=NULL; + int retval; + + D(("called.")); + + /* identify user */ + + retval = pam_get_item(pamh,PAM_USER,(const void **)&uname); + D(("user = `%s'", uname)); + if (retval != PAM_SUCCESS || uname == NULL) { + _log_err(LOG_ALERT + , "acct; could not identify user (from uid=%d)" + , getuid()); + return PAM_USER_UNKNOWN; + } + + /* get database information for user */ + + retval = pwdb_locate("user", PWDB_DEFAULT, uname, PWDB_ID_UNKNOWN, &pw); + if (retval != PWDB_SUCCESS || pw == NULL) { + + _log_err(LOG_ALERT, "acct; %s (%s from uid=%d)" + , pwdb_strerror(retval), uname, getuid()); + if ( pw ) { + (void) pwdb_delete(&pw); + } + return PAM_USER_UNKNOWN; + } + + /* now check the user's times etc.. */ + + retval = _shadow_acct_mgmt_exp(pamh, ctrl, pw, uname); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, "expiry check failed for '%s'", uname); + } + + /* Done with pw */ + + (void) pwdb_delete(&pw); + + /* all done */ + + D(("done.")); + return retval; +} + +/* + * Copyright (c) Elliot Lee, 1996. + * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996. + * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c new file mode 100644 index 00000000..14d74b74 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c @@ -0,0 +1,131 @@ +/* + * $Id: pam_unix_auth.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * + * See end of file for Copyright information. + */ + +static const char rcsid_auth[] = +"$Id: pam_unix_auth.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $: pam_unix_auth.-c,v 1.2 1996/09/05 06:46:53 morgan Exp morgan $\n" +" - PAM_PWDB authentication functions. <morgan@parc.power.net>"; + +/* + * _unix_auth() is a front-end for UNIX/shadow authentication + * + * First, obtain the password from the user. Then use a + * routine in 'support.-c' to authenticate the user. + */ + +#define _UNIX_AUTHTOK "-UN*X-PASS" + +static int _unix_auth(pam_handle_t *pamh, unsigned int ctrl) +{ + int retval; + const char *name, *p; + + D(("called.")); + + /* get the user'name' */ + + retval = _unix_get_user(pamh, ctrl, NULL, &name); + if (retval != PAM_SUCCESS ) { + if (retval != PAM_CONV_AGAIN) { + if ( on(UNIX_DEBUG,ctrl) ) { + _log_err(LOG_DEBUG, "auth could not identify user"); + } + } else { + D(("pam_get_user/conv() function is not ready yet")); + /* it is safe to resume this function so we translate this + retval to the value that indicates we're happy to resume. */ + retval = PAM_INCOMPLETE; + } + return retval; + } + + /* if this user does not have a password... */ + + if ( _unix_blankpasswd(ctrl, name) ) { + D(("user '%s' has blank passwd", name)); + name = NULL; + return PAM_SUCCESS; + } + + /* get this user's authentication token */ + + retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL + , _UNIX_AUTHTOK, &p); + if (retval != PAM_SUCCESS) { + if (retval != PAM_CONV_AGAIN) { + _log_err(LOG_CRIT, "auth could not identify password for [%s]" + , name); + } else { + D(("conversation function is not ready yet")); + /* it is safe to resume this function so we translate this + retval to the value that indicates we're happy to resume. */ + retval = PAM_INCOMPLETE; + } + name = NULL; + return retval; + } + D(("user=%s, password=[%s]", name, p)); + + /* verify the password of this user */ + retval = _unix_verify_password(pamh, name, p, ctrl); + name = p = NULL; + + D(("done [%d]", retval)); + + return retval; +} + +/* + * This function is for setting unix credentials. Sun has indicated + * that there are *NO* authentication credentials for unix. The + * obvious credentials would be the group membership of the user as + * listed in the /etc/group file. However, Sun indicates that it is + * the responsibility of the application to set these. + */ + +static int _unix_set_credentials(pam_handle_t *pamh, unsigned int ctrl) +{ + D(("called <empty function> returning.")); + + return PAM_SUCCESS; +} + +/******************************************************************** + * Copyright (c) Alexander O. Yuriev, 1996. + * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996 + * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996, 1997 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_md.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_md.-c new file mode 100644 index 00000000..65476732 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_md.-c @@ -0,0 +1,73 @@ +/* + * This function is a front-end for the message digest algorithms used + * to compute the user's encrypted passwords. No reversible encryption + * is used here and I intend to keep it that way. + * + * While there are many sources of encryption outside the United + * States, it *may* be illegal to re-export reversible encryption + * computer code. Until such time as it is legal to export encryption + * software freely from the US, please do not send me any. (AGM) + */ + +/* this should have been defined in a header file.. Why wasn't it? AGM */ +extern char *crypt(const char *key, const char *salt); + +#include "md5.h" +#include "bigcrypt.-c" + +struct cfns { + const char *salt; + int len; + char * (* mdfn)(const char *key, const char *salt); +}; + +/* array of non-standard digest algorithms available */ + +#define N_MDS 1 +const static struct cfns cfn_list[N_MDS] = { + { "$1$", 3, Goodcrypt_md5 }, +}; + +static char *_pam_md(const char *key, const char *salt) +{ + char *x,*e=NULL; + int i; + + D(("called with key='%s', salt='%s'", key, salt)); + + /* check for non-standard salts */ + + for (i=0; i<N_MDS; ++i) { + if ( !strncmp(cfn_list[i].salt, salt, cfn_list[i].len) ) { + e = cfn_list[i].mdfn(key, salt); + break; + } + } + + if ( i >= N_MDS ) { + e = bigcrypt(key, salt); /* (defaults to standard algorithm) */ + } + + x = x_strdup(e); /* put e in malloc()ed memory */ + _pam_overwrite(e); /* clean up */ + return x; /* this must be deleted elsewhere */ +} + +#ifndef PWDB_NO_MD_COMPAT +static char *_pam_md_compat(const char *key, const char *salt) +{ + char *x,*e=NULL; + + D(("called with key='%s', salt='%s'", key, salt)); + + if ( !strncmp("$1$", salt, 3) ) { + e = Brokencrypt_md5(key, salt); + x = x_strdup(e); /* put e in malloc()ed memory */ + _pam_overwrite(e); /* clean up */ + } else { + x = x_strdup(""); /* called from only one place so this is safe */ + } + + return x; /* this must be deleted elsewhere */ +} +#endif /* PWDB_NO_MD_COMPAT */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c new file mode 100644 index 00000000..dc106431 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c @@ -0,0 +1,373 @@ +/* $Id: pam_unix_passwd.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ */ + +static const char rcsid_pass[] = +"$Id: pam_unix_passwd.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $\n" +" - PAM_PWDB password module <morgan@parc.power.net>" +; + +#include "pam_unix_pwupd.-c" + +/* passwd/salt conversion macros */ + +#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') +#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') + +/* data tokens */ + +#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS" +#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS" + +/* Implementation */ + +/* + * i64c - convert an integer to a radix 64 character + */ +static int i64c(int i) +{ + if (i < 0) + return ('.'); + else if (i > 63) + return ('z'); + if (i == 0) + return ('.'); + if (i == 1) + return ('/'); + if (i >= 2 && i <= 11) + return ('0' - 2 + i); + if (i >= 12 && i <= 37) + return ('A' - 12 + i); + if (i >= 38 && i <= 63) + return ('a' - 38 + i); + return ('\0'); +} + +/* + * FUNCTION: _pam_unix_chauthtok() + * + * this function works in two passes. The first, when UNIX__PRELIM is + * set, obtains the previous password. It sets the PAM_OLDAUTHTOK item + * or stores it as a data item. The second function obtains a new + * password (verifying if necessary, that the user types it the same a + * second time.) depending on the 'ctrl' flags this new password may + * be stored in the PAM_AUTHTOK item or a private data item. + * + * Having obtained a new password. The function updates the + * /etc/passwd (and optionally the /etc/shadow) file(s). + * + * Provision is made for the creation of a blank shadow file if none + * is available, but one is required to update the shadow file -- the + * intention being for shadow passwords to be seamlessly implemented + * from the generic UNIX scheme. -- THIS BIT IS PRE-ALPHA.. and included + * in this release (.52) mostly for the purpose of discussion. + */ + +static int _unix_chauthtok(pam_handle_t *pamh, unsigned int ctrl) +{ + int retval; + unsigned int lctrl; + + /* <DO NOT free() THESE> */ + const char *user; + const char *pass_old, *pass_new; + /* </DO NOT free() THESE> */ + + D(("called")); + + /* + * First get the name of a user + */ + + retval = _unix_get_user( pamh, ctrl, "Username: ", &user ); + if ( retval != PAM_SUCCESS ) { + if ( on(UNIX_DEBUG,ctrl) ) { + _log_err(LOG_DEBUG, "password - could not identify user"); + } + return retval; + } + + if ( on(UNIX__PRELIM, ctrl) ) { + /* + * obtain and verify the current password (OLDAUTHTOK) for + * the user. + */ + + char *Announce; + + D(("prelim check")); + + if ( _unix_blankpasswd(ctrl, user) ) { + + return PAM_SUCCESS; + + } else if ( off(UNIX__IAMROOT, ctrl) ) { + + /* instruct user what is happening */ +#define greeting "Changing password for " + Announce = (char *) malloc(sizeof(greeting)+strlen(user)); + if (Announce == NULL) { + _log_err(LOG_CRIT, "password - out of memory"); + return PAM_BUF_ERR; + } + (void) strcpy(Announce, greeting); + (void) strcpy(Announce+sizeof(greeting)-1, user); +#undef greeting + + lctrl = ctrl; + set(UNIX__OLD_PASSWD, lctrl); + retval = _unix_read_password( pamh, lctrl + , Announce + , "(current) UNIX password: " + , NULL + , _UNIX_OLD_AUTHTOK + , &pass_old ); + free(Announce); + + if ( retval != PAM_SUCCESS ) { + _log_err(LOG_NOTICE + , "password - (old) token not obtained"); + return retval; + } + + /* verify that this is the password for this user */ + + retval = _unix_verify_password(pamh, user, pass_old, ctrl); + } else { + D(("process run by root so do nothing this time around")); + pass_old = NULL; + retval = PAM_SUCCESS; /* root doesn't have too */ + } + + if ( retval != PAM_SUCCESS ) { + D(("Authentication failed")); + pass_old = NULL; + return retval; + } + + retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); + pass_old = NULL; + if ( retval != PAM_SUCCESS ) { + _log_err(LOG_CRIT, "failed to set PAM_OLDAUTHTOK"); + } + + } else if ( on( UNIX__UPDATE, ctrl ) ) { + /* tpass is used below to store the _pam_md() return; it + * should be _pam_delete()'d. */ + + char *tpass=NULL; + + /* + * obtain the proposed password + */ + + D(("do update")); + + /* + * get the old token back. NULL was ok only if root [at this + * point we assume that this has already been enforced on a + * previous call to this function]. + */ + + if ( off(UNIX_NOT_SET_PASS, ctrl) ) { + retval = pam_get_item(pamh, PAM_OLDAUTHTOK + , (const void **)&pass_old); + } else { + retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK + , (const void **)&pass_old); + if (retval == PAM_NO_MODULE_DATA) { + retval = PAM_SUCCESS; + pass_old = NULL; + } + } + + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, "user not authenticated"); + return retval; + } + + D(("get new password now")); + + lctrl = ctrl; + + /* + * use_authtok is to force the use of a previously entered + * password -- needed for pluggable password strength checking + */ + + if ( on(UNIX_USE_AUTHTOK, lctrl) ) { + set(UNIX_USE_FIRST_PASS, lctrl); + } + + retval = _unix_read_password( pamh, lctrl + , NULL + , "Enter new UNIX password: " + , "Retype new UNIX password: " + , _UNIX_NEW_AUTHTOK + , &pass_new ); + + if ( retval != PAM_SUCCESS ) { + if ( on(UNIX_DEBUG,ctrl) ) { + _log_err(LOG_ALERT + , "password - new password not obtained"); + } + pass_old = NULL; /* tidy up */ + return retval; + } + + D(("returned to _unix_chauthtok")); + + /* + * At this point we know who the user is and what they + * propose as their new password. Verify that the new + * password is acceptable. + */ + + if (pass_new[0] == '\0') { /* "\0" password = NULL */ + pass_new = NULL; + } + + retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); + + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, "new password not acceptable"); + pass_new = pass_old = NULL; /* tidy up */ + return retval; + } + + /* + * By reaching here we have approved the passwords and must now + * rebuild the password database file. + * + * This includes the fact that the password is _not_ NULL. + */ + + /* + * First we encrypt the new password. + * + * XXX - this is where we might need some code for RADIUS types + * of password handling... no encryption needed.. + */ + + if ( on(UNIX_MD5_PASS, ctrl) ) { + + /* + * Code lifted from Marek Michalkiewicz's shadow suite. (CG) + * removed use of static variables (AGM) + */ + + struct timeval tv; + MD5_CTX ctx; + unsigned char result[16]; + char *cp = (char *)result; + unsigned char tmp[16]; + int i; + + GoodMD5Init(&ctx); + gettimeofday(&tv, (struct timezone *) 0); + GoodMD5Update(&ctx, (void *) &tv, sizeof tv); + i = getpid(); + GoodMD5Update(&ctx, (void *) &i, sizeof i); + i = clock(); + GoodMD5Update(&ctx, (void *) &i, sizeof i); + GoodMD5Update(&ctx, result, sizeof result); + GoodMD5Final(tmp, &ctx); + strcpy(cp, "$1$"); /* magic for the MD5 */ + cp += strlen(cp); + for (i = 0; i < 8; i++) + *cp++ = i64c(tmp[i] & 077); + *cp = '\0'; + + /* no longer need cleartext */ + pass_new = tpass = _pam_md(pass_new, (const char *)result); + + } else { + /* + * Salt manipulation is stolen from Rick Faith's passwd + * program. Sorry Rick :) -- alex + */ + + time_t tm; + char salt[3]; + + time(&tm); + salt[0] = bin_to_ascii(tm & 0x3f); + salt[1] = bin_to_ascii((tm >> 6) & 0x3f); + salt[2] = '\0'; + + if ( off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8 ) { + /* to avoid using the _extensions_ of the bigcrypt() + function we truncate the newly entered password */ + char *temp = malloc(9); + + if (temp == NULL) { + _log_err(LOG_CRIT, "out of memory for password"); + pass_new = pass_old = NULL; /* tidy up */ + return PAM_BUF_ERR; + } + + /* copy first 8 bytes of password */ + strncpy(temp, pass_new, 8); + temp[8] = '\0'; + + /* no longer need cleartext */ + pass_new = tpass = _pam_md( temp, salt ); + + _pam_delete(temp); /* tidy up */ + } else { + /* no longer need cleartext */ + pass_new = tpass = _pam_md( pass_new, salt ); + } + } + + D(("password processed")); + + /* update the password database(s) -- race conditions..? */ + + retval = unix_update_db(pamh, ctrl, user, pass_old, pass_new); + pass_old = pass_new = NULL; + + } else { /* something has broken with the module */ + + _log_err(LOG_ALERT, "password received unknown request"); + retval = PAM_ABORT; + + } + + return retval; +} + +/* ****************************************************************** + * Copyright (c) Alexander O. Yuriev (alex@bach.cis.temple.edu), 1996. + * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996, 1997. + * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c new file mode 100644 index 00000000..adb286e2 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c @@ -0,0 +1,260 @@ +/* + * $Id: pam_unix_pwupd.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $ + * + * This file contains the routines to update the passwd databases. + */ + +/* Implementation */ + +static int unix_update_db(pam_handle_t *pamh, int ctrl, const char *user, + const char *pass_old, const char *pass_new) +{ + const struct pwdb *pw=NULL; + const struct pwdb_entry *pwe=NULL; + pwdb_flag flag; + int retval, i; + + D(("called.")); + + /* obtain default user record */ + + retval = pwdb_locate("user", PWDB_DEFAULT, user, PWDB_ID_UNKNOWN, &pw); + if (retval == PWDB_PASS_PHRASE_REQD) { + retval = pwdb_set_entry(pw, "pass_phrase" + , pass_old, 1+strlen(pass_old) + , NULL, NULL, 0); + if (retval == PWDB_SUCCESS) + retval = pwdb_locate("user", pw->source, user + , PWDB_ID_UNKNOWN, &pw); + } + pass_old = NULL; + + if ( retval != PWDB_SUCCESS ) { + _log_err(LOG_ALERT, "cannot identify user %s (uid=%d)" + , user, getuid() ); + pass_new = NULL; + if (pw) + (void) pwdb_delete(&pw); + return PAM_USER_UNKNOWN; + } + + /* check that we can update all of the default databases */ + + retval = pwdb_flags("user", pw->source, &flag); + + if ( retval != PWDB_SUCCESS || ( pwdb_on(flag,PWDB_F_NOUPDATE) ) ) { + _log_err(LOG_ERR, "cannot update default database for user %s" + , user ); + pass_new = NULL; + if (pw) + (void) pwdb_delete(&pw); + return PAM_PERM_DENIED; + } + + /* If there was one, we delete the "last_change" entry */ + retval = pwdb_get_entry(pw, "last_change", &pwe); + if (retval == PWDB_SUCCESS) { + (void) pwdb_entry_delete(&pwe); + pwdb_set_entry(pw, "last_change", NULL, -1, NULL, NULL, 0); + } + + /* + * next check for pam.conf specified databases: shadow etc... [In + * other words, pam.conf indicates which database the password is + * to be subsequently placed in: this is password migration]. + */ + + if ( on(UNIX__SET_DB, ctrl) ) { + const char *db_token; + pwdb_type pt = _PWDB_MAX_TYPES; + + if ( on(UNIX_UNIX, ctrl) ) { + db_token = "U"; /* XXX - should be macro */ + pt = PWDB_UNIX; + } else if ( on(UNIX_SHADOW, ctrl) ) { + db_token = "x"; /* XXX - should be macro */ + pt = PWDB_SHADOW; + } else if ( on(UNIX_RADIUS, ctrl) ) { + db_token = "R"; /* XXX - is this ok? */ + pt = PWDB_RADIUS; + } else { + _log_err(LOG_ALERT + , "cannot determine database to use for authtok"); + pass_new = NULL; + if (pw) + (void) pwdb_delete(&pw); + return PAM_ABORT; /* we're in trouble */ + } + + /* + * Attempt to update the indicated database (only) + */ + + { + pwdb_type tpt[2]; + tpt[0] = pt; + tpt[1] = _PWDB_MAX_TYPES; + + /* Can we set entry in database? */ + retval = pwdb_flags("user", tpt, &flag); + if (retval == PWDB_SUCCESS && !pwdb_on(flag,PWDB_F_NOUPDATE)) { + /* YES. This database is available.. */ + + /* Only update if it is not already in the default list */ + for (i=0; pw->source[i] != _PWDB_MAX_TYPES + && pw->source[i] != pt ; ++i); + if (pw->source[i] == _PWDB_MAX_TYPES) { + const struct pwdb *tpw=NULL; + + /* copy database entry */ + if ((retval = pwdb_new(&tpw, 10)) != PWDB_SUCCESS + || (retval = pwdb_merge(tpw, pw, PWDB_TRUE)) + != PWDB_SUCCESS) { + _log_err(LOG_CRIT, "failed to obtain new pwdb: %s" + , pwdb_strerror(retval)); + retval = PAM_ABORT; + } else + retval = PAM_SUCCESS; + + /* set db_token */ + if (retval == PAM_SUCCESS) { + retval = pwdb_set_entry(tpw, "defer_pass", db_token + , 1+strlen(db_token) + , NULL, NULL, 0); + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "set defer_pass -> %s" + , pwdb_strerror(retval)); + retval = PAM_PERM_DENIED; + } else + retval = PAM_SUCCESS; + } + + /* update specific database */ + if (retval == PAM_SUCCESS) { + retval = pwdb_replace("user", tpt + , user, PWDB_ID_UNKNOWN, &tpw); + if (retval != PWDB_SUCCESS) { + const char *service=NULL; + (void) pam_get_item(pamh, PAM_SERVICE + , (const void **)&service); + _log_err(LOG_ALERT + , "(%s) specified database failed: %s" + , service + , pwdb_strerror(retval)); + retval = PAM_PERM_DENIED; + } else { + retval = PAM_SUCCESS; + } + } + + /* clean up temporary pwdb */ + if (tpw) + (void) pwdb_delete(&tpw); + } + + /* we can properly adopt new defer_pass */ + if (retval == PAM_SUCCESS) { + /* failing here will mean we go back to former + password location */ + (void) pwdb_set_entry(pw, "defer_pass", db_token + , 1+strlen(db_token), NULL, NULL, 0); + } + } + } + } + + /* + * the password will now be placed in appropriate (perhaps original) db + */ + + retval = pwdb_get_entry(pw, "uid", &pwe); + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "no uid!? (%s); %s", user, pwdb_strerror(retval)); + pass_new = NULL; + if (pw) + (void) pwdb_delete(&pw); + return PAM_USER_UNKNOWN; + } + + /* insert the passwd into the 'pw' structure */ + + retval = pwdb_set_entry(pw, "passwd", pass_new, 1+strlen(pass_new) + , NULL, NULL, 0); + pass_new = NULL; + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "set2 failed; %s", pwdb_strerror(retval)); + if (pw) + (void) pwdb_delete(&pw); + return PAM_AUTHTOK_LOCK_BUSY; + } + + retval = pwdb_replace("user", pw->source, user + , *((uid_t *)pwe->value), &pw); + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "user (%s/%d) update failed; %s" + , user, *((uid_t *)pwe->value), pwdb_strerror(retval)); + if (pw) + (void) pwdb_delete(&pw); + (void) pwdb_entry_delete(&pwe); + return PAM_ABORT; + } + + if (retval != PWDB_SUCCESS) { + + _log_err(LOG_ALERT, "user (%s/%d) update failed; %s" + , user, *((uid_t *)pwe->value), pwdb_strerror(retval)); + retval = PAM_ABORT; + + } else { + /* password updated */ + + _log_err(LOG_INFO, "password for (%s/%d) changed by (%s/%d)" + , user, *((uid_t *)pwe->value), getlogin(), getuid()); + retval = PAM_SUCCESS; + } + + /* tidy up */ + + (void) pwdb_entry_delete(&pwe); + if (pw) + (void) pwdb_delete(&pw); + + return retval; +} + +/* ****************************************************************** + * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996,1997. + * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997. + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c new file mode 100644 index 00000000..3e03fc55 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c @@ -0,0 +1,98 @@ +/* + * $Id: pam_unix_sess.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $ + * + * See end for Copyright information + */ + +static const char rcsid_sess[] = +"$Id: pam_unix_sess.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $\n" +" - PAM_PWDB session management. morgan@parc.power.net"; + +/* Define internal functions */ + +static int _unix_open_session(pam_handle_t *pamh, unsigned int ctrl) +{ + int retval; + char *user_name, *service; + + D(("called.")); + + retval = pam_get_item( pamh, PAM_USER, (void *) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + _log_err(LOG_CRIT, "open_session - error recovering username"); + return PAM_SESSION_ERR; + } + + retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service ); + if ( service == NULL || retval != PAM_SUCCESS ) { + _log_err(LOG_CRIT, "open_session - error recovering service"); + return PAM_SESSION_ERR; + } + + _log_err(LOG_INFO, "(%s) session opened for user %s by %s(uid=%d)" + , service, user_name + , getlogin() == NULL ? "":getlogin(), getuid() ); + + return PAM_SUCCESS; +} + +static int _unix_close_session(pam_handle_t *pamh, unsigned int ctrl) +{ + int retval; + char *user_name, *service; + + D(("called.")); + + retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + _log_err(LOG_CRIT, "close_session - error recovering username"); + return PAM_SESSION_ERR; + } + + retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service ); + if ( service == NULL || retval != PAM_SUCCESS ) { + _log_err(LOG_CRIT, "close_session - error recovering service"); + return PAM_SESSION_ERR; + } + + _log_err(LOG_INFO, "(%s) session closed for user %s" + , service, user_name ); + + return PAM_SUCCESS; +} + +/* + * Copyright (c) Alexander O. Yuriev, 1996. All rights reserved. + * Copyright (c) Andrew G. Morgan, 1996, <morgan@parc.power.net> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c b/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c new file mode 100644 index 00000000..0b55c952 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c @@ -0,0 +1,221 @@ +/* + * $Id: pwdb_chkpwd.c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ + * + * This program is designed to run setuid(root) or with sufficient + * privilege to read all of the unix password databases. It is designed + * to provide a mechanism for the current user (defined by this + * process' real uid) to verify their own password. + * + * The password is read from the standard input. The exit status of + * this program indicates whether the user is authenticated or not. + * + * Copyright information is located at the end of the file. + * + */ + +#include <security/_pam_aconf.h> + +#ifdef MEMORY_DEBUG +# undef exit +# undef strdup +# undef free +#endif /* MEMORY_DEBUG */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + +#include <security/_pam_macros.h> + +#define MAXPASS 200 /* the maximum length of a password */ + +#define UNIX_PASSED (PWDB_SUCCESS) +#define UNIX_FAILED (PWDB_SUCCESS+1) + +#include <pwdb/pwdb_public.h> + +/* syslogging function for errors and other information */ + +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pwdb_chkpwd", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +#define PWDB_NO_MD_COMPAT +#include "pam_unix_md.-c" + +static int _unix_verify_passwd(const char *salt, const char *p) +{ + char *pp=NULL; + int retval; + + if (p == NULL) { + if (*salt == '\0') { + retval = UNIX_PASSED; + } else { + retval = UNIX_FAILED; + } + } else { + pp = _pam_md(p, salt); + p = NULL; /* no longer needed here */ + + if ( strcmp( pp, salt ) == 0 ) { + retval = UNIX_PASSED; + } else { + retval = UNIX_FAILED; + } + } + + /* clean up */ + { + char *tp = pp; + if (pp != NULL) { + while(tp && *tp) + *tp++ = '\0'; + free(pp); + pp = tp = NULL; + } + } + + return retval; +} + +int main(int argc, char **argv) +{ + const struct pwdb *pw=NULL; + const struct pwdb_entry *pwe=NULL; + char pass[MAXPASS+1]; + int npass, force_failure=0; + int retval=UNIX_FAILED; + + /* + * we establish that this program is running with non-tty stdin. + * this is to discourage casual use. It does *NOT* prevent an + * intruder from repeatadly running this program to determine the + * password of the current user (brute force attack, but one for + * which the attacker must already have gained access to the user's + * account). + */ + + if ( isatty(STDIN_FILENO) ) { + _log_err(LOG_NOTICE + , "inappropriate use of PWDB helper binary [UID=%d]" + , getuid() ); + fprintf(stderr, + "This program is not designed for running in this way\n" + "-- the system administrator has been informed\n"); + exit(UNIX_FAILED); + } + + /* + * determine the current user's name: + */ + + retval = pwdb_start(); + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "failed to open pwdb"); + retval = UNIX_FAILED; + } + if (retval != UNIX_FAILED) { + retval = pwdb_locate("user", PWDB_DEFAULT, PWDB_NAME_UNKNOWN, + getuid(), &pw); + } + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "could not identify user"); + while (pwdb_end() != PWDB_SUCCESS); + exit(UNIX_FAILED); + } + if (argc == 2) { + if (pwdb_get_entry(pw, "user", &pwe) == PWDB_SUCCESS) { + if (pwe == NULL) { + force_failure = 1; + } else { + if (strcmp((const char *) pwe->value, argv[1])) { + force_failure = 1; + } + pwdb_entry_delete(&pwe); + } + } + } + + /* read the password from stdin (a pipe from the pam_pwdb module) */ + + npass = read(STDIN_FILENO, pass, MAXPASS); + + if (npass < 0) { /* is it a valid password? */ + _log_err(LOG_DEBUG, "no password supplied"); + retval = UNIX_FAILED; + } else if (npass >= MAXPASS-1) { + _log_err(LOG_DEBUG, "password too long"); + retval = UNIX_FAILED; + } else if (pwdb_get_entry(pw, "passwd", &pwe) != PWDB_SUCCESS) { + _log_err(LOG_WARNING, "password not found"); + retval = UNIX_FAILED; + } else { + if (npass <= 0) { + /* the password is NULL */ + + retval = _unix_verify_passwd((const char *)(pwe->value), NULL); + } else { + /* does pass agree with the official one? */ + + pass[npass] = '\0'; /* NUL terminate */ + retval = _unix_verify_passwd((const char *)(pwe->value), pass); + } + } + + memset(pass, '\0', MAXPASS); /* clear memory of the password */ + while (pwdb_end() != PWDB_SUCCESS); + + if ((retval != UNIX_FAILED) && force_failure) { + retval = UNIX_FAILED; + } + + /* return pass or fail */ + + exit(retval); +} + +/* + * Copyright (c) Andrew G. Morgan, 1997. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_pwdb/support.-c b/Linux-PAM/modules/pam_pwdb/support.-c new file mode 100644 index 00000000..623fe2c3 --- /dev/null +++ b/Linux-PAM/modules/pam_pwdb/support.-c @@ -0,0 +1,943 @@ +/* + * $Id: support.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ + * + * Copyright information at end of file. + */ + +/* + * here is the string to inform the user that the new passwords they + * typed were not the same. + */ + +#define MISTYPED_PASS "Sorry, passwords do not match" + +/* type definition for the control options */ + +typedef struct { + const char *token; + unsigned int mask; /* shall assume 32 bits of flags */ + unsigned int flag; +} UNIX_Ctrls; + +/* + * macro to determine if a given flag is on + */ + +#define on(x,ctrl) (unix_args[x].flag & ctrl) + +/* + * macro to determine that a given flag is NOT on + */ + +#define off(x,ctrl) (!on(x,ctrl)) + +/* + * macro to turn on/off a ctrl flag manually + */ + +#define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag) +#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag)) + +/* the generic mask */ + +#define _ALL_ON_ (~0U) + +/* end of macro definitions definitions for the control flags */ + +/* ****************************************************************** * + * ctrl flags proper.. + */ + +/* + * here are the various options recognized by the unix module. They + * are enumerated here and then defined below. Internal arguments are + * given NULL tokens. + */ + +#define UNIX__OLD_PASSWD 0 /* internal */ +#define UNIX__VERIFY_PASSWD 1 /* internal */ +#define UNIX__IAMROOT 2 /* internal */ + +#define UNIX_AUDIT 3 /* print more things than debug.. + some information may be sensitive */ +#define UNIX_USE_FIRST_PASS 4 +#define UNIX_TRY_FIRST_PASS 5 +#define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */ + +#define UNIX__PRELIM 7 /* internal */ +#define UNIX__UPDATE 8 /* internal */ +#define UNIX__NONULL 9 /* internal */ +#define UNIX__QUIET 10 /* internal */ +#define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */ +#define UNIX_SHADOW 12 /* signal shadow on */ +#define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */ +#define UNIX__NULLOK 14 /* Null token ok */ +#define UNIX_RADIUS 15 /* wish to use RADIUS for password */ +#define UNIX__SET_DB 16 /* internal - signals redirect to db */ +#define UNIX_DEBUG 17 /* send more info to syslog(3) */ +#define UNIX_NODELAY 18 /* admin does not want a fail-delay */ +#define UNIX_UNIX 19 /* wish to use /etc/passwd for pwd */ +#define UNIX_BIGCRYPT 20 /* use DEC-C2 crypt()^x function */ +#define UNIX_LIKE_AUTH 21 /* need to auth for setcred to work */ +/* -------------- */ +#define UNIX_CTRLS_ 22 /* number of ctrl arguments defined */ + + +static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = { +/* symbol token name ctrl mask ctrl * + * ------------------ ------------------ -------------- ---------- */ + +/* UNIX__OLD_PASSWD */ { NULL, _ALL_ON_, 01 }, +/* UNIX__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 }, +/* UNIX__IAMROOT */ { NULL, _ALL_ON_, 04 }, +/* UNIX_AUDIT */ { "audit", _ALL_ON_, 010 }, +/* UNIX_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(060), 020 }, +/* UNIX_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(060), 040 }, +/* UNIX_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 0100 }, +/* UNIX__PRELIM */ { NULL, _ALL_ON_^(0600), 0200 }, +/* UNIX__UPDATE */ { NULL, _ALL_ON_^(0600), 0400 }, +/* UNIX__NONULL */ { NULL, _ALL_ON_, 01000 }, +/* UNIX__QUIET */ { NULL, _ALL_ON_, 02000 }, +/* UNIX_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 04000 }, +/* UNIX_SHADOW */ { "shadow", _ALL_ON_^(0140000), 010000 }, +/* UNIX_MD5_PASS */ { "md5", _ALL_ON_^(02000000), 020000 }, +/* UNIX__NULLOK */ { "nullok", _ALL_ON_^(01000), 0 }, +/* UNIX_RADIUS */ { "radius", _ALL_ON_^(0110000), 040000 }, +/* UNIX__SET_DB */ { NULL, _ALL_ON_, 0100000 }, +/* UNIX_DEBUG */ { "debug", _ALL_ON_, 0200000 }, +/* UNIX_NODELAY */ { "nodelay", _ALL_ON_, 0400000 }, +/* UNIX_UNIX */ { "unix", _ALL_ON_^(050000), 01000000 }, +/* UNIX_BIGCRYPT */ { "bigcrypt", _ALL_ON_^(020000), 02000000 }, +/* UNIX_LIKE_AUTH */ { "likeauth", _ALL_ON_, 04000000 }, +}; + +#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) + +/* syslogging function for errors and other information */ + +static void _log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM_pwdb", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* this is a front-end for module-application conversations */ + +static int converse(pam_handle_t *pamh, int ctrl, int nargs + , struct pam_message **message + , struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse")); + + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS ) { + + retval = conv->conv(nargs, ( const struct pam_message ** ) message + , response, conv->appdata_ptr); + + D(("returned from application's conversation function")); + + if (retval != PAM_SUCCESS && on(UNIX_DEBUG,ctrl) ) { + _log_err(LOG_DEBUG, "conversation failure [%s]" + , pam_strerror(pamh, retval)); + } + + } else if (retval != PAM_CONV_AGAIN) { + _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" + , pam_strerror(pamh, retval)); + } + + D(("ready to return from module conversation")); + + return retval; /* propagate error status */ +} + +static int make_remark(pam_handle_t *pamh, unsigned int ctrl + , int type, const char *text) +{ + int retval=PAM_SUCCESS; + + if ( off(UNIX__QUIET, ctrl) ) { + struct pam_message *pmsg[1], msg[1]; + struct pam_response *resp; + + pmsg[0] = &msg[0]; + msg[0].msg = text; + msg[0].msg_style = type; + + resp = NULL; + retval = converse(pamh, ctrl, 1, pmsg, &resp); + + if (resp) { + _pam_drop_reply(resp, 1); + } + } + return retval; +} + +/* + * set the control flags for the UNIX module. + */ + +static int set_ctrl(int flags, int argc, const char **argv) +{ + unsigned int ctrl; + + D(("called.")); + + ctrl = UNIX_DEFAULTS; /* the default selection of options */ + + /* set some flags manually */ + + if ( getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK) ) { + set(UNIX__IAMROOT, ctrl); + } + if ( flags & PAM_UPDATE_AUTHTOK ) { + set(UNIX__UPDATE, ctrl); + } + if ( flags & PAM_PRELIM_CHECK ) { + set(UNIX__PRELIM, ctrl); + } + if ( flags & PAM_DISALLOW_NULL_AUTHTOK ) { + set(UNIX__NONULL, ctrl); + } + if ( flags & PAM_SILENT ) { + set(UNIX__QUIET, ctrl); + } + + /* now parse the arguments to this module */ + + while (argc-- > 0) { + int j; + + D(("pam_pwdb arg: %s",*argv)); + + for (j=0; j<UNIX_CTRLS_; ++j) { + if (unix_args[j].token + && ! strcmp(*argv, unix_args[j].token) ) { + break; + } + } + + if ( j >= UNIX_CTRLS_ ) { + _log_err(LOG_ERR, "unrecognized option [%s]",*argv); + } else { + ctrl &= unix_args[j].mask; /* for turning things off */ + ctrl |= unix_args[j].flag; /* for turning things on */ + } + + ++argv; /* step to next argument */ + } + + /* these are used for updating passwords in specific places */ + + if (on(UNIX_SHADOW,ctrl) || on(UNIX_RADIUS,ctrl) || on(UNIX_UNIX,ctrl)) { + set(UNIX__SET_DB, ctrl); + } + + /* auditing is a more sensitive version of debug */ + + if ( on(UNIX_AUDIT,ctrl) ) { + set(UNIX_DEBUG, ctrl); + } + + /* return the set of flags */ + + D(("done.")); + return ctrl; +} + +/* use this to free strings. ESPECIALLY password strings */ + +static char *_pam_delete(register char *xx) +{ + _pam_overwrite(xx); + _pam_drop(xx); + return NULL; +} + +static void _cleanup(pam_handle_t *pamh, void *x, int error_status) +{ + x = _pam_delete( (char *) x ); +} + +/* ************************************************************** * + * Useful non-trivial functions * + * ************************************************************** */ + +#include "pam_unix_md.-c" + +/* + * the following is used to keep track of the number of times a user fails + * to authenticate themself. + */ + +#define FAIL_PREFIX "-UN*X-FAIL-" +#define UNIX_MAX_RETRIES 3 + +struct _pam_failed_auth { + char *user; /* user that's failed to be authenticated */ + char *name; /* attempt from user with name */ + int id; /* uid of name'd user */ + int count; /* number of failures so far */ +}; + +#ifndef PAM_DATA_REPLACE +#error "Need to get an updated libpam 0.52 or better" +#endif + +static void _cleanup_failures(pam_handle_t *pamh, void *fl, int err) +{ + int quiet; + const char *service=NULL; + struct _pam_failed_auth *failure; + + D(("called")); + + quiet = err & PAM_DATA_SILENT; /* should we log something? */ + err &= PAM_DATA_REPLACE; /* are we just replacing data? */ + failure = (struct _pam_failed_auth *) fl; + + if ( failure != NULL ) { + + if ( !quiet && !err ) { /* under advisement from Sun,may go away */ + + /* log the number of authentication failures */ + if ( failure->count > 1 ) { + (void) pam_get_item(pamh, PAM_SERVICE + , (const void **)&service); + _log_err(LOG_NOTICE + , "%d more authentication failure%s; %s(uid=%d) -> " + "%s for %s service" + , failure->count-1, failure->count==2 ? "":"s" + , failure->name + , failure->id + , failure->user + , service == NULL ? "**unknown**":service + ); + if ( failure->count > UNIX_MAX_RETRIES ) { + _log_err(LOG_ALERT + , "service(%s) ignoring max retries; %d > %d" + , service == NULL ? "**unknown**":service + , failure->count + , UNIX_MAX_RETRIES ); + } + } + } + failure->user = _pam_delete(failure->user); /* tidy up */ + failure->name = _pam_delete(failure->name); /* tidy up */ + free(failure); + } +} + +/* + * verify the password of a user + */ + +#include <sys/types.h> +#include <sys/wait.h> + +static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd, + const char *user) +{ + int retval, child, fds[2]; + + D(("called.")); + /* create a pipe for the password */ + if (pipe(fds) != 0) { + D(("could not make pipe")); + return PAM_AUTH_ERR; + } + + /* fork */ + child = fork(); + if (child == 0) { + static char *args[] = { NULL, NULL, NULL }; + static char *envp[] = { NULL }; + + /* XXX - should really tidy up PAM here too */ + while (pwdb_end() == PWDB_SUCCESS); + + /* reopen stdin as pipe */ + close(fds[1]); + dup2(fds[0], STDIN_FILENO); + + /* exec binary helper */ + args[0] = x_strdup(CHKPWD_HELPER); + args[1] = x_strdup(user); + + execve(CHKPWD_HELPER, args, envp); + + /* should not get here: exit with error */ + D(("helper binary is not available")); + exit(PWDB_SUCCESS+1); + } else if (child > 0) { + /* wait for child */ + if (passwd != NULL) { /* send the password to the child */ + write(fds[1], passwd, strlen(passwd)+1); + passwd = NULL; + } else { + write(fds[1], "", 1); /* blank password */ + } + close(fds[0]); /* we close this after the write because we want + to avoid a possible SIGPIPE. */ + close(fds[1]); + (void) waitpid(child, &retval, 0); /* wait for helper to complete */ + retval = (retval == PWDB_SUCCESS) ? PAM_SUCCESS:PAM_AUTH_ERR; + } else { + D(("fork failed")); + retval = PAM_AUTH_ERR; + } + + D(("returning %d", retval)); + return retval; +} + +static int _unix_verify_password(pam_handle_t *pamh, const char *name, + const char *p, unsigned int ctrl) +{ + const struct pwdb *pw=NULL; + const struct pwdb_entry *pwe=NULL; + + const char *salt; + char *pp; + char *data_name; + int retval; + int verify_result; + + D(("called")); + +#ifdef HAVE_PAM_FAIL_DELAY + if ( off(UNIX_NODELAY, ctrl) ) { + D(("setting delay")); + (void) pam_fail_delay(pamh, 1000000); /* 1 sec delay for on failure */ + } +#endif + + /* locate the entry for this user */ + + D(("locating user's record")); + retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw); + if (retval == PWDB_PASS_PHRASE_REQD) { + /* + * give the password to the pwdb library. It may be needed to + * access the database + */ + + retval = pwdb_set_entry( pw, "pass_phrase", p, 1+strlen(p) + , NULL, NULL, 0); + if (retval != PWDB_SUCCESS) { + _log_err(LOG_ALERT, "find pass; %s", pwdb_strerror(retval)); + (void) pwdb_delete(&pw); + p = NULL; + return PAM_CRED_INSUFFICIENT; + } + + retval = pwdb_locate("user", pw->source, name, PWDB_ID_UNKNOWN, &pw); + } + + if (retval != PWDB_SUCCESS) { + D(("user's record unavailable")); + if ( on(UNIX_AUDIT, ctrl) ) { + /* this might be a typo and the user has given a password + instead of a username. Careful with this. */ + _log_err(LOG_ALERT, "check pass; user (%s) unknown", name); + } else { + _log_err(LOG_ALERT, "check pass; user unknown"); + } + (void) pwdb_delete(&pw); + p = NULL; + return PAM_USER_UNKNOWN; + } + + /* + * courtesy of PWDB the password for the user is stored in + * encrypted form in the "passwd" entry of pw. + */ + + retval = pwdb_get_entry(pw, "passwd", &pwe); + if (retval != PWDB_SUCCESS) { + if (geteuid()) { + /* we are not root perhaps this is the reason? Run helper */ + D(("running helper binary")); + retval = pwdb_run_helper_binary(pamh, p, name); + } else { + retval = PAM_AUTHINFO_UNAVAIL; + _log_err(LOG_ALERT, "get passwd; %s", pwdb_strerror(retval)); + } + (void) pwdb_delete(&pw); + p = NULL; + return retval; + } + salt = (const char *) pwe->value; + + /* + * XXX: Cristian, the above is not the case for RADIUS(?) Some + * lines should be added for RADIUS to verify the password in + * clear text... + */ + + data_name = (char *) malloc(sizeof(FAIL_PREFIX)+strlen(name)); + if ( data_name == NULL ) { + _log_err(LOG_CRIT, "no memory for data-name"); + } + strcpy(data_name, FAIL_PREFIX); + strcpy(data_name + sizeof(FAIL_PREFIX)-1, name); + + if ( !( (salt && *salt) || (p && *p) ) ) { + + D(("two null passwords to compare")); + + /* the stored password is NULL */ + pp = NULL; + if ( off(UNIX__NONULL, ctrl ) ) { /* this means we've succeeded */ + verify_result = PAM_SUCCESS; + } else { + verify_result = PAM_AUTH_ERR; + } + + } else if ( !( salt && p ) ) { + + D(("one of the two to compare are NULL")); + + pp = NULL; + verify_result = PAM_AUTH_ERR; + + } else { + + /* there is no way that p can be NULL (one can be "") */ + pp = _pam_md(p, salt); + + /* the moment of truth -- do we agree with the password? */ + D(("comparing state of pp[%s] and salt[%s]", pp, salt)); + + if ( strcmp( pp, salt ) == 0 ) { + verify_result = PAM_SUCCESS; + } else { + _pam_delete(pp); + pp = _pam_md_compat(p, salt); + if ( strcmp( pp, salt ) == 0 ) { + verify_result = PAM_SUCCESS; + } else { + verify_result = PAM_AUTH_ERR; + } + } + + p = NULL; /* no longer needed here */ + + } + + if ( verify_result == PAM_SUCCESS ) { + + retval = PAM_SUCCESS; + if (data_name) { /* reset failures */ + pam_set_data(pamh, data_name, NULL, _cleanup_failures); + } + + } else { + + retval = PAM_AUTH_ERR; + if (data_name != NULL) { + struct _pam_failed_auth *new=NULL; + const struct _pam_failed_auth *old=NULL; + + /* get a failure recorder */ + + new = (struct _pam_failed_auth *) + malloc(sizeof(struct _pam_failed_auth)); + + if (new != NULL) { + + new->user = x_strdup(name); + new->id = getuid(); + new->name = x_strdup(getlogin() ? getlogin():"" ); + + /* any previous failures for this user ? */ + pam_get_data(pamh, data_name, (const void **)&old ); + + if (old != NULL) { + new->count = old->count +1; + if (new->count >= UNIX_MAX_RETRIES) { + retval = PAM_MAXTRIES; + } + } else { + const char *service=NULL; + (void) pam_get_item(pamh, PAM_SERVICE + , (const void **)&service); + _log_err(LOG_NOTICE + , "authentication failure; %s(uid=%d) -> " + "%s for %s service" + , new->name + , new->id + , new->user + , service == NULL ? "**unknown**":service + ); + new->count = 1; + } + + pam_set_data(pamh, data_name, new, _cleanup_failures); + + } else { + _log_err(LOG_CRIT, "no memory for failure recorder"); + } + } + + } + + (void) pwdb_entry_delete(&pwe); + (void) pwdb_delete(&pw); + salt = NULL; + _pam_delete(data_name); + _pam_delete(pp); + + D(("done [%d].", retval)); + + return retval; +} + +/* + * this function obtains the name of the current user and ensures + * that the PAM_USER item is set to this value + */ + +static int _unix_get_user(pam_handle_t *pamh, unsigned int ctrl + , const char *prompt, const char **user) +{ + int retval; + + D(("called")); + + retval = pam_get_user(pamh, user, prompt); + if (retval != PAM_SUCCESS) { + D(("trouble reading username")); + return retval; + } + + /* + * Various libraries at various times have had bugs related to + * '+' or '-' as the first character of a user name. Don't take + * any chances here. Require that the username starts with an + * alphanumeric character. + */ + + if (*user == NULL || !isalnum(**user)) { + D(("bad username")); + if (on(UNIX_DEBUG,ctrl)) { + _log_err(LOG_ERR, "bad username [%s]", *user); + } + return PAM_USER_UNKNOWN; + } + + if (retval == PAM_SUCCESS && on(UNIX_DEBUG,ctrl)) { + _log_err(LOG_DEBUG, "username [%s] obtained", *user); + } + + return retval; +} + +/* + * _unix_blankpasswd() is a quick check for a blank password + * + * returns TRUE if user does not have a password + * - to avoid prompting for one in such cases (CG) + */ + +static int _unix_blankpasswd(unsigned int ctrl, const char *name) +{ + const struct pwdb *pw=NULL; + const struct pwdb_entry *pwe=NULL; + int retval; + + D(("called")); + + /* + * This function does not have to be too smart if something goes + * wrong, return FALSE and let this case to be treated somewhere + * else (CG) + */ + + if ( on(UNIX__NONULL, ctrl) ) + return 0; /* will fail but don't let on yet */ + + /* find the user's database entry */ + + retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw); + if (retval != PWDB_SUCCESS || pw == NULL ) { + + retval = 0; + + } else { + + /* Does this user have a password? */ + + retval = pwdb_get_entry(pw, "passwd", &pwe); + if ( retval != PWDB_SUCCESS || pwe == NULL ) + retval = 0; + else if ( pwe->value == NULL || ((char *)pwe->value)[0] == '\0' ) + retval = 1; + else + retval = 0; + + } + + /* tidy up */ + + if ( pw ) { + (void) pwdb_delete(&pw); + if ( pwe ) + (void) pwdb_entry_delete(&pwe); + } + + return retval; +} + +/* + * obtain a password from the user + */ + +static int _unix_read_password( pam_handle_t *pamh + , unsigned int ctrl + , const char *comment + , const char *prompt1 + , const char *prompt2 + , const char *data_name + , const char **pass ) +{ + int authtok_flag; + int retval; + const char *item; + char *token; + + D(("called")); + + /* + * make sure nothing inappropriate gets returned + */ + + *pass = token = NULL; + + /* + * which authentication token are we getting? + */ + + authtok_flag = on(UNIX__OLD_PASSWD,ctrl) ? PAM_OLDAUTHTOK:PAM_AUTHTOK ; + + /* + * should we obtain the password from a PAM item ? + */ + + if ( on(UNIX_TRY_FIRST_PASS,ctrl) || on(UNIX_USE_FIRST_PASS,ctrl) ) { + retval = pam_get_item(pamh, authtok_flag, (const void **) &item); + if (retval != PAM_SUCCESS ) { + /* very strange. */ + _log_err(LOG_ALERT + , "pam_get_item returned error to unix-read-password" + ); + return retval; + } else if (item != NULL) { /* we have a password! */ + *pass = item; + item = NULL; + return PAM_SUCCESS; + } else if (on(UNIX_USE_FIRST_PASS,ctrl)) { + return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ + } else if (on(UNIX_USE_AUTHTOK, ctrl) + && off(UNIX__OLD_PASSWD, ctrl)) { + return PAM_AUTHTOK_RECOVER_ERR; + } + } + + /* + * getting here implies we will have to get the password from the + * user directly. + */ + + { + struct pam_message msg[3],*pmsg[3]; + struct pam_response *resp; + int i, replies; + + /* prepare to converse */ + + if ( comment != NULL && off(UNIX__QUIET, ctrl) ) { + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = comment; + i = 1; + } else { + i = 0; + } + + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = prompt1; + replies = 1; + + if ( prompt2 != NULL ) { + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = prompt2; + ++replies; + } + + /* so call the conversation expecting i responses */ + resp = NULL; + retval = converse(pamh, ctrl, i, pmsg, &resp); + + if (resp != NULL) { + + /* interpret the response */ + + if (retval == PAM_SUCCESS) { /* a good conversation */ + + token = x_strdup(resp[i-replies].resp); + if (token != NULL) { + if (replies == 2) { + + /* verify that password entered correctly */ + if (!resp[i-1].resp + || strcmp(token,resp[i-1].resp)) { + token = _pam_delete(token); /* mistyped */ + retval = PAM_AUTHTOK_RECOVER_ERR; + make_remark(pamh, ctrl + , PAM_ERROR_MSG, MISTYPED_PASS); + } + } + + } else { + _log_err(LOG_NOTICE + , "could not recover authentication token"); + } + + } + + /* + * tidy up the conversation (resp_retcode) is ignored + * -- what is it for anyway? AGM + */ + + _pam_drop_reply(resp, i); + + } else { + retval = (retval == PAM_SUCCESS) + ? PAM_AUTHTOK_RECOVER_ERR:retval ; + } + } + + if (retval != PAM_SUCCESS) { + if ( on(UNIX_DEBUG,ctrl) ) + _log_err(LOG_DEBUG,"unable to obtain a password"); + return retval; + } + + /* 'token' is the entered password */ + + if ( off(UNIX_NOT_SET_PASS, ctrl) ) { + + /* we store this password as an item */ + + retval = pam_set_item(pamh, authtok_flag, token); + token = _pam_delete(token); /* clean it up */ + if ( retval != PAM_SUCCESS + || (retval = pam_get_item(pamh, authtok_flag + , (const void **)&item)) + != PAM_SUCCESS ) { + + _log_err(LOG_CRIT, "error manipulating password"); + return retval; + + } + + } else { + /* + * then store it as data specific to this module. pam_end() + * will arrange to clean it up. + */ + + retval = pam_set_data(pamh, data_name, (void *) token, _cleanup); + if (retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, "error manipulating password data [%s]" + , pam_strerror(pamh, retval) ); + token = _pam_delete(token); + return retval; + } + item = token; + token = NULL; /* break link to password */ + } + + *pass = item; + item = NULL; /* break link to password */ + + return PAM_SUCCESS; +} + +static int _pam_unix_approve_pass(pam_handle_t *pamh + , unsigned int ctrl + , const char *pass_old + , const char *pass_new) +{ + D(("&new=%p, &old=%p",pass_old,pass_new)); + D(("new=[%s]",pass_new)); + D(("old=[%s]",pass_old)); + + if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { + if ( on(UNIX_DEBUG, ctrl) ) { + _log_err(LOG_DEBUG, "bad authentication token"); + } + make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? + "No password supplied":"Password unchanged" ); + return PAM_AUTHTOK_ERR; + } + + /* + * if one wanted to hardwire authentication token strength + * checking this would be the place - AGM + */ + + return PAM_SUCCESS; +} + +/* ****************************************************************** * + * Copyright (c) Andrew G. Morgan 1996-8. + * Copyright (c) Alex O. Yuriev, 1996. + * Copyright (c) Cristian Gafton 1996. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + diff --git a/Linux-PAM/modules/pam_radius/Makefile b/Linux-PAM/modules/pam_radius/Makefile new file mode 100644 index 00000000..aa149d3e --- /dev/null +++ b/Linux-PAM/modules/pam_radius/Makefile @@ -0,0 +1,95 @@ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Cristian Gafton <gafton@redhat.com> 1996/09/10 +# +# STATIC modules are not supported +# + +include ../../Make.Rules + +TITLE=pam_radius +CONFD=$(CONFIGED)/security +export CONFD +CONFILE=$(CONFD)/radius.conf +export CONFILE + +ifeq ($(HAVE_LIBPWDB),yes) + +# + +LIBSRC = $(TITLE).c +LIBOBJ = $(TITLE).o + +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +#LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +#static/%.o : %.c +# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif + +#ifdef STATIC +#LIBSTATIC = lib$(TITLE).o +#endif + +####################### don't edit below ####################### + +all: dirs $(LIBSHARED) $(LIBSTATIC) register + +dirs: +ifdef DYNAMIC + $(MKDIR) ./dynamic +endif +#ifdef STATIC +# $(MKDIR) ./static +#endif + +register: +#ifdef STATIC +# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +#endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) -lpwdb +endif + +#ifdef STATIC +#$(LIBOBJS): $(LIBSRC) +# +#$(LIBSTATIC): $(LIBOBJS) +# $(LD) -r -o $@ $(LIBOBJS) -lpwdb +#endif + +install: all +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) core *~ + rm -f *.a *.o *.so *.bak dynamic/* static/* + rm -rf dynamic static + +.c.o: + $(CC) $(CFLAGS) -c $< + +else + +include ../dont_makefile + +endif diff --git a/Linux-PAM/modules/pam_radius/README b/Linux-PAM/modules/pam_radius/README new file mode 100644 index 00000000..253308fd --- /dev/null +++ b/Linux-PAM/modules/pam_radius/README @@ -0,0 +1,58 @@ + +pam_radius module: + RADIUS session module. + +WHAT IT DOES: + This module is intended to provide the session service for users +autheticated with a RADIUS server. At the present stage, the only option +supported is the use of the RADIUS server as an accounting server. There are +few things which needs to be cleared out first in the PAM project until one +will be able to use this module and expect it to magically start pppd in +response to a RADIUS server command to use PPP for this user, or to initiate +a telnet connection to another host, or to hang and call back the user using +parameters provided in the RADIUS server response. Most of these things are +better suited for the radius login application. I hope to make available +Real Soon (tm) patches for the login apps to make it work this way. + + +ARGUMENTS RECOGNIZED: + debug verbose logging + +MODULE SERVICES PROVIDED: + session _open_session and _close_session + + When opening a session, this module sends an Accounting-Start +message to the RADIUS server, which will log/update/whatever a database for +this user. On close, an Accounting-Stop message is sent to the RADIUS +server. + +This module have no other pre-requisites for making it work. One can install +a RADIUS server just for fun and use it as a centralized accounting server and +forget about wtmp/last/sac&comp :-) + +USAGE: + For the services you need this module (login for example) put + the following line in /etc/pam.conf as the last line for that + service (usually after the pam_unix session line): + + login session required /lib/security/pam_radius.so + + Replace "login" for each service you are using this module. + + This module make extensive use of the API provided in libpwdb + 0.54preB or later. By default, it will read the radius server + configuration (hostname and secret) from /etc/raddb/server. This is + a default compiled into libpwdb, and curently there is no way to + modify this default without recompiling libpwdb. I am working on + extending the radius support from libpwdb to provide a possibility + to make this runtime-configurable. + + Also please note that libpwdb will require also the RADIUS + dictionary to be present (/etc/raddb/dictionary). + +TODO: + The work is far from complete. Deal with "real" session things. + +AUTHOR: + Cristian Gafton <gafton@redhat.com> + diff --git a/Linux-PAM/modules/pam_radius/pam_radius.c b/Linux-PAM/modules/pam_radius/pam_radius.c new file mode 100644 index 00000000..b412edf9 --- /dev/null +++ b/Linux-PAM/modules/pam_radius/pam_radius.c @@ -0,0 +1,193 @@ +/* + * pam_radius + * Process an user session according to a RADIUS server response + * + * 1.0 - initial release - Linux ONLY + * 1.1 - revised and reorganized for libpwdb 0.54preB or higher + * - removed the conf= parameter, since we use libpwdb exclusively now + * + * See end for Copyright information + */ + +#if !(defined(linux)) +#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! +#endif + +/* Module defines */ +#define BUFFER_SIZE 1024 +#define LONG_VAL_PTR(ptr) ((*(ptr)<<24)+(*((ptr)+1)<<16)+(*((ptr)+2)<<8)+(*((ptr)+3))) + +#define PAM_SM_SESSION + +#include "pam_radius.h" + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +static time_t session_time; + +/* we need to save these from open_session to close_session, since + * when close_session will be called we won't be root anymore and + * won't be able to access again the radius server configuration file + * -- cristiang */ + +static RADIUS_SERVER rad_server; +static char hostname[BUFFER_SIZE]; +static char secret[BUFFER_SIZE]; + +/* logging */ +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pam_radius", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x0001 + +static int _pam_parse(int argc, const char **argv) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + +/* now the session stuff */ +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval; + char *user_name; + int ctrl; + + ctrl = _pam_parse(argc, argv); + retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + _pam_log(LOG_CRIT, "open_session - error recovering username"); + return PAM_SESSION_ERR; + } + + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "starting RADIUS user session for '%s'", + user_name); + + retval = get_server_entries(hostname, secret); + if ((retval != PWDB_RADIUS_SUCCESS) || + !strlen(hostname) || !strlen(secret)) { + _pam_log(LOG_CRIT, "Could not determine the radius server to talk to"); + return PAM_IGNORE; + } + session_time = time(NULL); + rad_server.hostname = hostname; + rad_server.secret = secret; + retval = radius_acct_start(rad_server, user_name); + if (retval != PWDB_RADIUS_SUCCESS) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server"); + return PAM_IGNORE; + } + + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int ctrl; + char *user_name; + int retval; + + ctrl = _pam_parse(argc, argv); + retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + _pam_log(LOG_CRIT, "open_session - error recovering username"); + return PAM_SESSION_ERR; + } + + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "closing RADIUS user session for '%s'", + user_name); + + if (!strlen(hostname) || !strlen(secret)) { + _pam_log(LOG_CRIT, "Could not determine the radius server to talk to"); + return PAM_IGNORE; + } + retval = radius_acct_stop(rad_server, user_name, + time(NULL) - session_time); + if (retval != PWDB_RADIUS_SUCCESS) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server"); + return PAM_IGNORE; + } + + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_radius_modstruct = { + "pam_radius", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL +}; +#endif + +/* + * Copyright (c) Cristian Gafton, 1996, <gafton@redhat.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_radius/pam_radius.h b/Linux-PAM/modules/pam_radius/pam_radius.h new file mode 100644 index 00000000..8193c844 --- /dev/null +++ b/Linux-PAM/modules/pam_radius/pam_radius.h @@ -0,0 +1,40 @@ +/* + * $Id: pam_radius.h,v 1.1.1.1 2001/04/29 04:17:32 hartmans Exp $ + */ + +#ifndef PAM_RADIUS_H +#define PAM_RADIUS_H + +#include <security/_pam_aconf.h> + +#include <stdio.h> + +#ifndef __USE_POSIX2 +#define __USE_POSIX2 +#endif /* __USE_POSIX2 */ + +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/resource.h> + +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <syslog.h> +#include <stdarg.h> +#include <utmp.h> +#include <time.h> +#include <netdb.h> + +#include <netinet/in.h> +#include <rpcsvc/ypclnt.h> +#include <rpc/rpc.h> + +#include <pwdb/radius.h> +#include <pwdb/pwdb_radius.h> + +/******************************************************************/ + +#endif /* PAM_RADIUS_H */ diff --git a/Linux-PAM/modules/pam_rhosts/Makefile b/Linux-PAM/modules/pam_rhosts/Makefile new file mode 100644 index 00000000..0c4ec77e --- /dev/null +++ b/Linux-PAM/modules/pam_rhosts/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:32 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_rhosts_auth + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_rhosts/README b/Linux-PAM/modules/pam_rhosts/README new file mode 100644 index 00000000..d2e93d1d --- /dev/null +++ b/Linux-PAM/modules/pam_rhosts/README @@ -0,0 +1,57 @@ +arguments recognized: + +"no_hosts_equiv" +"no_rhosts" +"debug" +"nowarn" +"suppress" +"promiscuous" + +.rhosts/hosts.equiv format: + +There are positive entries, when one is matched authentication +succeeds and terminates. There are negative entries, when one is +matched authentication fails and terminates. Thus order is +significant. + +Entry hosts.equiv .rhosts +<host> All users on <host> are ok Same username from <host> is ok +<host> <user> <user> from <host> is ok ditto +-<host> No users from <host> are ok ditto +<host> -<user> <user> from <host> is not ok ditto + +<host> can be ip (IPv4) numbers. + +Netgroups may be used in either host or user fields, and then applies +to all hosts, or users, in the netgroup. The syntax is + + +@<ng> + +The entries + + <host> +@<ng> + +@<ng> +@<ng> + +@<ng> <user> + +means exactly what you think it does. Negative entries are of the +form + + -@<ng> + +When the "promiscuous" option is given the special character + may be +used as a wildcard in any field. + + + Allow anyone from any host to connect. DANGEROUS. + + + Ditto. + + <user> Allow the user to connect from anywhere. DANGEROUS. + <host> + Allow any user from the host. Dangerous. + +These, perhaps more useful, forms of the + form is also disallowed +unless "promiscuous" is specified: + + + -<user> Disallow the user from any host + + -@<ng> Disallow all members of the netgroup from any host + +When "promiscuous" is not specified a '+' is handled as a negative +match. + diff --git a/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c b/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c new file mode 100644 index 00000000..7266b4e8 --- /dev/null +++ b/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c @@ -0,0 +1,795 @@ +/*---------------------------------------------------------------------- + * Modified for Linux-PAM by Al Longyear <longyear@netcom.com> 96/5/5 + * Modifications, Cristian Gafton 97/2/8 + * Modifications, Peter Allgeyer 97/3 + * Modifications (netgroups and fixes), Nicolai Langfeldt 97/3/21 + * Security fix: 97/10/2 - gethostbyname called repeatedly without care + * Modification (added privategroup option) Andrew <morgan@transmeta.com> + *---------------------------------------------------------------------- + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <security/_pam_aconf.h> + +#define USER_RHOSTS_FILE "/.rhosts" /* prefixed by user's home dir */ + +#ifdef linux +#include <endian.h> +#endif + +#ifdef HAVE_SYS_FSUID_H +#include <sys/fsuid.h> +#endif /* HAVE_SYS_FSUID_H */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> /* This is supposed(?) to contain the following */ +int innetgr(const char *, const char *, const char *,const char *); + +#include <stdio.h> +#include <errno.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#ifndef MAXDNAME +#define MAXDNAME 256 +#endif + +#include <stdarg.h> +#include <ctype.h> + +#include <net/if.h> +#ifdef linux +# include <linux/sockios.h> +# ifndef __USE_MISC +# define __USE_MISC +# include <sys/fsuid.h> +# endif /* __USE_MISC */ +#endif + +#include <pwd.h> +#include <grp.h> +#include <sys/file.h> +#include <sys/signal.h> +#include <sys/stat.h> +#include <syslog.h> +#ifndef _PATH_HEQUIV +#define _PATH_HEQUIV "/etc/hosts.equiv" +#endif /* _PATH_HEQUIV */ + +#define PAM_SM_AUTH /* only defines this management group */ + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> +#include <security/_pam_modutil.h> + +/* to the best of my knowledge, all modern UNIX boxes have 32 bit integers */ +#define U32 unsigned int + + +/* + * Options for this module + */ + +struct _options { + int opt_no_hosts_equiv; + int opt_hosts_equiv_rootok; + int opt_no_rhosts; + int opt_debug; + int opt_nowarn; + int opt_disallow_null_authtok; + int opt_silent; + int opt_promiscuous; + int opt_suppress; + int opt_private_group; + int opt_no_uid_check; + const char *superuser; + const char *last_error; +}; + +/* logging */ +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("pam_rhosts_auth", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static void set_option (struct _options *opts, const char *arg) +{ + if (strcmp(arg, "no_hosts_equiv") == 0) { + opts->opt_no_hosts_equiv = 1; + return; + } + + if (strcmp(arg, "hosts_equiv_rootok") == 0) { + opts->opt_hosts_equiv_rootok = 1; + return; + } + + if (strcmp(arg, "no_rhosts") == 0) { + opts->opt_no_rhosts = 1; + return; + } + + if (strcmp(arg, "debug") == 0) { + D(("debugging enabled")); + opts->opt_debug = 1; + return; + } + + if (strcmp(arg, "no_warn") == 0) { + opts->opt_nowarn = 1; + return; + } + + if (strcmp(arg, "promiscuous") == 0) { + opts->opt_promiscuous = 1; /* used to permit '+' in ...hosts file */ + return; + } + + if (strcmp(arg, "suppress") == 0) { + opts->opt_suppress = 1; /* used to suppress failure warning message */ + return; + } + + if (strcmp(arg, "privategroup") == 0) { + opts->opt_private_group = 1; /* used to permit group write on .rhosts + file if group has same name as owner */ + return; + } + + if (strcmp(arg, "no_uid_check") == 0) { + opts->opt_no_uid_check = 1; /* NIS optimization */ + return; + } + + if (strcmp(arg, "superuser=") == 0) { + opts->superuser = arg+sizeof("superuser=")-1; + return; + } + /* + * All other options are ignored at the present time. + */ + _pam_log(LOG_WARNING, "unrecognized option '%s'", arg); +} + +static void set_parameters (struct _options *opts, int flags, + int argc, const char **argv) +{ + opts->opt_silent = flags & PAM_SILENT; + opts->opt_disallow_null_authtok = flags & PAM_DISALLOW_NULL_AUTHTOK; + + while (argc-- > 0) { + set_option (opts, *argv); + ++argv; + } +} + +/* + * Obtain the name of the remote host. Currently, this is simply by + * requesting the contents of the PAM_RHOST item. + */ + +static int pam_get_rhost(pam_handle_t *pamh, const char **rhost + , const char *prompt) +{ + int retval; + const char *current; + + retval = pam_get_item (pamh, PAM_RHOST, (const void **)¤t); + if (retval != PAM_SUCCESS) + return retval; + + if (current == NULL) { + return PAM_AUTH_ERR; + } + *rhost = current; + + return retval; /* pass on any error from conversation */ +} + +/* + * Obtain the name of the remote user. Currently, this is simply by + * requesting the contents of the PAM_RUSER item. + */ + +static int pam_get_ruser(pam_handle_t *pamh, const char **ruser, + const char *prompt) +{ + int retval; + const char *current; + + retval = pam_get_item (pamh, PAM_RUSER, (const void **)¤t); + if (retval != PAM_SUCCESS) { + return retval; + } + + if (current == NULL) { + return PAM_AUTH_ERR; + } + *ruser = current; + + return retval; /* pass on any error from conversation */ +} + +/* + * Returns 1 if positive match, 0 if no match, -1 if negative match. + */ + +static int +__icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr + , register char *lhost, const char *rhost) +{ + struct hostent *hp; + U32 laddr; + int negate=1; /* Multiply return with this to get -1 instead of 1 */ + char **pp, *user; + + /* Check nis netgroup. We assume that pam has done all needed + paranoia checking before we are handed the rhost */ + if (strncmp("+@",lhost,2) == 0) + return(innetgr(&lhost[2],rhost,NULL,NULL)); + + if (strncmp("-@",lhost,2) == 0) + return(-innetgr(&lhost[2],rhost,NULL,NULL)); + + /* -host */ + if (strncmp("-",lhost,1) == 0) { + negate=-1; + lhost++; + } else if (strcmp("+",lhost) == 0) { + (void) pam_get_item(pamh, PAM_USER, (const void **)&user); + D(("user %s has a `+' host entry", user)); + if (opts->opt_promiscuous) + return (1); /* asking for trouble, but ok.. */ + /* If not promiscuous: handle as negative */ + return (-1); + } else if (strncmp("+",lhost,1) == 0) { + /* '+hostname' is supposed to be equivalent to 'hostname' */ + lhost++; + } + + + /* Try for raw ip address first. */ + if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) + return (negate*(! (raddr ^ laddr))); + + /* Better be a hostname. */ + hp = gethostbyname(lhost); + if (hp == NULL) + return (0); + + /* Spin through ip addresses. */ + for (pp = hp->h_addr_list; *pp; ++pp) + if (!memcmp (&raddr, *pp, sizeof (U32))) + return (negate); + + /* No match. */ + return (0); +} + +/* Returns 1 on positive match, 0 on no match, -1 on negative match */ + +static int __icheckuser(pam_handle_t *pamh, struct _options *opts + , const char *luser, const char *ruser + , const char *rhost) +{ + /* + luser is user entry from .rhosts/hosts.equiv file + ruser is user id on remote host + rhost is the remote host name + */ + char *user; + + /* [-+]@netgroup */ + if (strncmp("+@",luser,2) == 0) + return (innetgr(&luser[2],NULL,ruser,NULL)); + + if (strncmp("-@",luser,2) == 0) + return (-innetgr(&luser[2],NULL,ruser,NULL)); + + /* -user */ + if (strncmp("-",luser,1) == 0) + return(-(strcmp(&luser[1],ruser) == 0)); + + /* + */ + if (strcmp("+",luser) == 0) { + (void) pam_get_item(pamh, PAM_USER, (const void **)&user); + _pam_log(LOG_WARNING, "user %s has a `+' user entry", user); + if (opts->opt_promiscuous) + return(1); + /* If not promiscuous we handle it as a negative match */ + return(-1); + } + + /* simple string match */ + return (strcmp(ruser, luser) == 0); +} + +/* + * Returns 1 for blank lines (or only comment lines) and 0 otherwise + */ + +static int __isempty(char *p) +{ + while (*p && isspace(*p)) { + ++p; + } + + return (*p == '\0' || *p == '#') ? 1:0 ; +} + +/* + * Returns 0 if positive match, 1 if _not_ ok. + */ + +static int +__ivaliduser (pam_handle_t *pamh, struct _options *opts, + FILE *hostf, U32 raddr, + const char *luser, const char *ruser, const char *rhost) +{ + register const char *user; + register char *p; + int hcheck, ucheck; + char buf[MAXHOSTNAMELEN + 128]; /* host + login */ + + buf[sizeof (buf)-1] = '\0'; /* terminate line */ + + while (fgets(buf, sizeof(buf), hostf) != NULL) { /* hostf file line */ + p = buf; /* from beginning of file.. */ + + /* Skip empty or comment lines */ + if (__isempty(p)) { + continue; + } + + /* Skip lines that are too long. */ + if (strchr(p, '\n') == NULL) { + int ch = getc(hostf); + + while (ch != '\n' && ch != EOF) + ch = getc(hostf); + continue; + } + + /* + * If there is a hostname at the start of the line. Set it to + * lower case. A leading ' ' or '\t' indicates no hostname + */ + + for (;*p && !isspace(*p); ++p) { + *p = tolower(*p); + } + + /* + * next we want to find the permitted name for the remote user + */ + + if (*p == ' ' || *p == '\t') { + + /* <nul> terminate hostname and skip spaces */ + for (*p++='\0'; *p && isspace(*p); ++p); + + user = p; /* this is the user's name */ + while (*p && !isspace(*p)) + ++p; /* find end of user's name */ + } else + user = p; + + *p = '\0'; /* <nul> terminate username (+host?) */ + + /* buf -> host(?) ; user -> username(?) */ + + /* First check host part */ + hcheck=__icheckhost(pamh, opts, raddr, buf, rhost); + + if (hcheck<0) + return(1); + + if (hcheck) { + /* Then check user part */ + if (! (*user)) + user = luser; + + ucheck=__icheckuser(pamh, opts, user, ruser, rhost); + + /* Positive 'host user' match? */ + if (ucheck>0) + return(0); + + /* Negative 'host -user' match? */ + if (ucheck<0) + return(1); + + /* Neither, go on looking for match */ + } + } + + return (1); +} + +/* + * New .rhosts strategy: We are passed an ip address. We spin through + * hosts.equiv and .rhosts looking for a match. When the .rhosts only + * has ip addresses, we don't have to trust a nameserver. When it + * contains hostnames, we spin through the list of addresses the nameserver + * gives us and look for a match. + * + * Returns 0 if ok, -1 if not ok. + */ + +static int +pam_iruserok(pam_handle_t *pamh, + struct _options *opts, U32 raddr, int superuser, + const char *ruser, const char *luser, const char *rhost) +{ + const char *cp; + struct stat sbuf; + struct passwd *pwd; + FILE *hostf; + uid_t uid; + int answer; + char pbuf[MAXPATHLEN]; /* potential buffer overrun */ + + if ((!superuser||opts->opt_hosts_equiv_rootok) && !opts->opt_no_hosts_equiv ) { + + /* try to open system hosts.equiv file */ + hostf = fopen (_PATH_HEQUIV, "r"); + if (hostf) { + answer = __ivaliduser(pamh, opts, hostf, raddr, luser + , ruser, rhost); + (void) fclose(hostf); + if (answer == 0) + return 0; /* remote host is equivalent to localhost */ + } /* else { + No hosts.equiv file on system. + } */ + } + + if ( opts->opt_no_rhosts ) + return 1; + + /* + * Identify user's local .rhosts file + */ + + pwd = _pammodutil_getpwnam(pamh, luser); + if (pwd == NULL) { + /* + * luser is assumed to be valid because of an earlier check for uid = 0 + * we don't log this error twice. However, this shouldn't happen ! + * --cristiang + */ + return(1); + } + + /* check for buffer overrun */ + if (strlen(pwd->pw_dir) + sizeof(USER_RHOSTS_FILE) + 2 >= MAXPATHLEN) { + if (opts->opt_debug) + _pam_log(LOG_DEBUG,"home directory for `%s' is too long", luser); + return 1; /* to dangerous to try */ + } + + (void) strcpy(pbuf, pwd->pw_dir); + (void) strcat(pbuf, USER_RHOSTS_FILE); + + /* + * Change effective uid while _reading_ .rhosts. (not just + * opening). If root and reading an NFS mounted file system, + * can't read files that are 0600 as .rhosts files should be. + */ + + /* We are root, this will not fail */ +#ifdef linux + /* If we are on linux the better way is setfsuid */ + uid = setfsuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); +#else + uid = geteuid(); + (void) seteuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); +#endif + + if (hostf == NULL) { + if (opts->opt_debug) + _pam_log(LOG_DEBUG,"Could not open %s file",pbuf); + answer = 1; + goto exit_function; + } + + /* + * If not a regular file, or is owned by someone other than + * user or root or if writeable by anyone but the owner, quit. + */ + + cp = NULL; + if (lstat(pbuf, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)) + cp = ".rhosts not regular file"; + else if (fstat(fileno(hostf), &sbuf) < 0) + cp = ".rhosts fstat failed"; + else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) + cp = "bad .rhosts owner"; + else if (sbuf.st_mode & S_IWOTH) + cp = ".rhosts writable by other!"; + else if (sbuf.st_mode & S_IWGRP) { + + /* private group caveat */ + if (opts->opt_private_group) { + struct group *grp = getgrgid(sbuf.st_gid); + + if (NULL == grp || NULL == grp->gr_name + || strcmp(luser,grp->gr_name)) { + cp = ".rhosts writable by public group"; + } else if (grp->gr_mem) { + int gcount; + + /* require at most one member (luser) of this group */ + for (gcount=0; grp->gr_mem[gcount]; ++gcount) { + if (strcmp(grp->gr_mem[gcount], luser)) { + gcount = -1; + break; + } + } + if (gcount < 0) { + cp = ".rhosts writable by other members of group"; + } + } + } else { + cp = ".rhosts writable by group"; + } + + } /* It is _NOT_ safe to append an else here... Do so prior to + * S_IWGRP check */ + + /* If there were any problems, quit. */ + if (cp) { + opts->last_error = cp; + answer = 1; + goto exit_function; + } + + answer = __ivaliduser (pamh, opts, hostf, raddr, luser, ruser, rhost); + +exit_function: + /* + * Go here to exit after the fsuid/euid has been adjusted so that + * they are reset before we exit. + */ + +#ifdef linux + setfsuid(uid); +#else + (void)seteuid(uid); +#endif + + if (hostf != NULL) + (void) fclose(hostf); + + return answer; +} + +static int +pam_ruserok (pam_handle_t *pamh, + struct _options *opts, const char *rhost, int superuser, + const char *ruser, const char *luser) +{ + struct hostent *hp; + int answer = 1; /* default to failure */ + U32 *addrs; + int n, i; + + opts->last_error = (char *) 0; + hp = gethostbyname(rhost); /* identify host */ + + if (hp != NULL) { + /* First of all check the address length */ + if (hp->h_length != 4) { + _pam_log(LOG_ALERT, "pam_rhosts module can't work with not IPv4 " + "addresses"); + return 1; /* not allowed */ + } + + /* loop though address list */ + for (n = 0; hp->h_addr_list[n]; n++); + D(("rhosts: %d addresses", n)); + + if (n) { + addrs = calloc (n, hp->h_length); + for (i = 0; i < n; i++) + memcpy (addrs+i, hp->h_addr_list[i], hp->h_length); + + for (i = 0; i < n && answer; i++) { + D(("rhosts: address %d is %04x", i, addrs[i])); + answer = pam_iruserok(pamh, opts, addrs[i], superuser, + ruser, luser, rhost); + /* answer == 0 means success */ + } + + free (addrs); + } + } + + return answer; +} + +/* + * Internal function to do authentication + */ + +static int _pam_auth_rhosts (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + int retval; + const char *luser = NULL; + const char *ruser = NULL, *rhost = NULL; + struct _options opts; + int as_root = 0; + + /* + * Look at the options and set the flags accordingly. + */ + memset (&opts, 0, sizeof (opts)); + set_parameters (&opts, flags, argc, argv); + /* + * Obtain the parameters for the various items + */ + for (;;) { /* abuse loop to avoid goto */ + + /* get the remotehost */ + D(("getting rhost")); + retval = pam_get_rhost(pamh, &rhost, NULL); + (void) pam_set_item(pamh, PAM_RHOST, rhost); + if (retval != PAM_SUCCESS) { + if (opts.opt_debug) { + _pam_log(LOG_DEBUG, "could not get the remote host name"); + } + break; + } + + /* get the remote user */ + D(("getting ruser")); + retval = pam_get_ruser(pamh, &ruser, NULL); + (void) pam_set_item(pamh, PAM_RUSER, ruser); + if (retval != PAM_SUCCESS) { + if (opts.opt_debug) + _pam_log(LOG_DEBUG, "could not get the remote username"); + break; + } + + /* get the local user */ + D(("getting user")); + retval = pam_get_user(pamh, &luser, NULL); + if (retval != PAM_SUCCESS) { + if (opts.opt_debug) + _pam_log(LOG_DEBUG, "could not determine name of local user"); + break; + } + + if (opts.superuser && !strcmp(opts.superuser, luser)) { + as_root = 1; + } + + /* check if the luser uid == 0... --cristiang */ + if (! opts.opt_no_uid_check) { + struct passwd *luser_pwd; + + luser_pwd = _pammodutil_getpwnam(pamh, luser); + if (luser_pwd == NULL) { + if (opts.opt_debug) + _pam_log(LOG_DEBUG, "user '%s' unknown to this system", + luser); + retval = PAM_AUTH_ERR; + break; + } + if (luser_pwd->pw_uid == 0) + as_root = 1; + luser_pwd = NULL; /* forget */ + } +/* + * Validate the account information. + */ + if (pam_ruserok (pamh, &opts, rhost, as_root, ruser, luser) != 0) { + if ( !opts.opt_suppress ) { + _pam_log(LOG_WARNING, "denied to %s@%s as %s: %s", + ruser, rhost, luser, (opts.last_error==NULL) ? + "access not allowed":opts.last_error); + } + retval = PAM_AUTH_ERR; + } else { + _pam_log(LOG_NOTICE, "allowed to %s@%s as %s", + ruser, rhost, luser); + } + break; + } + + return retval; +} + +/* --- authentication management functions --- */ + +PAM_EXTERN +int pam_sm_authenticate (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + int retval; + + if (sizeof(U32) != 4) { + _pam_log (LOG_ALERT, "pam_rhosts module can\'t work on this hardware " + "(yet)"); + return PAM_AUTH_ERR; + } + sethostent(1); + retval = _pam_auth_rhosts (pamh, flags, argc, argv); + endhostent(); + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + +/* end of module definition */ + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_rhosts_auth_modstruct = { + "pam_rhosts_auth", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif diff --git a/Linux-PAM/modules/pam_rootok/Makefile b/Linux-PAM/modules/pam_rootok/Makefile new file mode 100644 index 00000000..f6c58635 --- /dev/null +++ b/Linux-PAM/modules/pam_rootok/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_rootok + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_rootok/README b/Linux-PAM/modules/pam_rootok/README new file mode 100644 index 00000000..4e19c097 --- /dev/null +++ b/Linux-PAM/modules/pam_rootok/README @@ -0,0 +1,18 @@ +# $Id: README,v 1.1.1.2 2002/09/15 20:08:57 hartmans Exp $ +# + +this module is an authentication module that performs one task: if the +id of the user is '0' then it returns 'PAM_SUCCESS' with the +'sufficient' /etc/pam.conf control flag it can be used to allow +password free access to some service for 'root' + +Recognized arguments: + + debug write a message to syslog indicating success or + failure. + +module services provided: + + auth _authentication and _setcred (blank) + +Andrew Morgan diff --git a/Linux-PAM/modules/pam_rootok/pam_rootok.c b/Linux-PAM/modules/pam_rootok/pam_rootok.c new file mode 100644 index 00000000..57ddebe5 --- /dev/null +++ b/Linux-PAM/modules/pam_rootok/pam_rootok.c @@ -0,0 +1,110 @@ +/* pam_rootok module */ + +/* + * $Id: pam_rootok.c,v 1.1.1.2 2002/09/15 20:08:57 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <string.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-rootok", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + + +/* argument parsing */ + +#define PAM_DEBUG_ARG 01 + +static int _pam_parse(int argc, const char **argv) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int ctrl; + int retval = PAM_AUTH_ERR; + + ctrl = _pam_parse(argc, argv); + if (getuid() == 0) + retval = PAM_SUCCESS; + + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "authentication %s" + , retval==PAM_SUCCESS ? "succeeded":"failed" ); + } + + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_rootok_modstruct = { + "pam_rootok", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_securetty/Makefile b/Linux-PAM/modules/pam_securetty/Makefile new file mode 100644 index 00000000..65e50d51 --- /dev/null +++ b/Linux-PAM/modules/pam_securetty/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_securetty + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_securetty/README b/Linux-PAM/modules/pam_securetty/README new file mode 100644 index 00000000..1df095c9 --- /dev/null +++ b/Linux-PAM/modules/pam_securetty/README @@ -0,0 +1,9 @@ +pam_securetty: + Allows root logins only if the user is logging in on a + "secure" tty, as defined by the listing in /etc/securetty + + Also checks to make sure that /etc/securetty is a plain + file and not world writable. + + - Elliot Lee <sopwith@redhat.com>, Red Hat Software. + July 25, 1996. diff --git a/Linux-PAM/modules/pam_securetty/pam_securetty.c b/Linux-PAM/modules/pam_securetty/pam_securetty.c new file mode 100644 index 00000000..9e6121e8 --- /dev/null +++ b/Linux-PAM/modules/pam_securetty/pam_securetty.c @@ -0,0 +1,191 @@ +/* pam_securetty module */ + +#define SECURETTY_FILE "/etc/securetty" +#define TTY_PREFIX "/dev/" + +/* + * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + * July 25, 1996. + * This code shamelessly ripped from the pam_rootok module. + * Slight modifications AGM. 1996/12/3 + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <pwd.h> +#include <string.h> + +#define PAM_SM_AUTH + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-securetty", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x0001 + +static int _pam_parse(int argc, const char **argv) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int retval = PAM_AUTH_ERR; + const char *username; + char *uttyname; + char ttyfileline[256]; + struct stat ttyfileinfo; + struct passwd *user_pwd; + FILE *ttyfile; + int ctrl; + + /* parse the arguments */ + ctrl = _pam_parse(argc, argv); + + retval = pam_get_user(pamh, &username, NULL); + if (retval != PAM_SUCCESS || username == NULL) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_WARNING, "cannot determine username"); + } + return (retval == PAM_CONV_AGAIN + ? PAM_INCOMPLETE:PAM_SERVICE_ERR); + } + + retval = pam_get_item(pamh, PAM_TTY, (const void **)&uttyname); + if (retval != PAM_SUCCESS || uttyname == NULL) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_WARNING, "cannot determine user's tty"); + } + return PAM_SERVICE_ERR; + } + + /* The PAM_TTY item may be prefixed with "/dev/" - skip that */ + if (strncmp(TTY_PREFIX, uttyname, sizeof(TTY_PREFIX)-1) == 0) + uttyname += sizeof(TTY_PREFIX)-1; + + user_pwd = getpwnam(username); + if (user_pwd == NULL) { + return PAM_IGNORE; + } else if (user_pwd->pw_uid != 0) { /* If the user is not root, + securetty's does not apply + to them */ + return PAM_SUCCESS; + } + + if (stat(SECURETTY_FILE, &ttyfileinfo)) { + _pam_log(LOG_NOTICE, "Couldn't open " SECURETTY_FILE); + return PAM_SUCCESS; /* for compatibility with old securetty handling, + this needs to succeed. But we still log the + error. */ + } + + if ((ttyfileinfo.st_mode & S_IWOTH) + || !S_ISREG(ttyfileinfo.st_mode)) { + /* If the file is world writable or is not a + normal file, return error */ + _pam_log(LOG_ERR, SECURETTY_FILE + " is either world writable or not a normal file"); + return PAM_AUTH_ERR; + } + + ttyfile = fopen(SECURETTY_FILE,"r"); + if(ttyfile == NULL) { /* Check that we opened it successfully */ + _pam_log(LOG_ERR, + "Error opening " SECURETTY_FILE); + return PAM_SERVICE_ERR; + } + /* There should be no more errors from here on */ + retval=PAM_AUTH_ERR; + /* This loop assumes that PAM_SUCCESS == 0 + and PAM_AUTH_ERR != 0 */ + while((fgets(ttyfileline,sizeof(ttyfileline)-1, ttyfile) != NULL) + && retval) { + if(ttyfileline[strlen(ttyfileline) - 1] == '\n') + ttyfileline[strlen(ttyfileline) - 1] = '\0'; + retval = strcmp(ttyfileline,uttyname); + } + fclose(ttyfile); + if(retval) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_WARNING, "access denied: tty '%s' is not secure !", + uttyname); + retval = PAM_AUTH_ERR; + } + if ((retval == PAM_SUCCESS) && (ctrl & PAM_DEBUG_ARG)) + _pam_log(LOG_DEBUG, "access allowed for '%s' on '%s'", + username, uttyname); + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_securetty_modstruct = { + "pam_securetty", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_shells/Makefile b/Linux-PAM/modules/pam_shells/Makefile new file mode 100644 index 00000000..1ead26c5 --- /dev/null +++ b/Linux-PAM/modules/pam_shells/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_shells + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_shells/README b/Linux-PAM/modules/pam_shells/README new file mode 100644 index 00000000..cbd5bfb5 --- /dev/null +++ b/Linux-PAM/modules/pam_shells/README @@ -0,0 +1,10 @@ +pam_shells: + Authentication is granted if the users shell is listed in + /etc/shells. If no shell is in /etc/passwd (empty), the + /bin/sh is used (following ftpd's convention). + + Also checks to make sure that /etc/shells is a plain + file and not world writable. + + - Erik Troan <ewt@redhat.com>, Red Hat Software. + August 5, 1996. diff --git a/Linux-PAM/modules/pam_shells/pam_shells.c b/Linux-PAM/modules/pam_shells/pam_shells.c new file mode 100644 index 00000000..36dd1a91 --- /dev/null +++ b/Linux-PAM/modules/pam_shells/pam_shells.c @@ -0,0 +1,133 @@ +/* pam_shells module */ + +#define SHELL_FILE "/etc/shells" + +/* + * by Erik Troan <ewt@redhat.com>, Red Hat Software. + * August 5, 1996. + * This code shamelessly ripped from the pam_securetty module. + */ + +#define _BSD_SOURCE + +#include <pwd.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <syslog.h> +#include <unistd.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-shells", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int retval = PAM_AUTH_ERR; + const char *userName; + char *userShell; + char shellFileLine[256]; + struct stat sb; + struct passwd * pw; + FILE * shellFile; + + retval = pam_get_user(pamh,&userName,NULL); + if(retval != PAM_SUCCESS) + return PAM_SERVICE_ERR; + + if(!userName || (strlen(userName) <= 0)) { + /* Don't let them use a NULL username... */ + pam_get_user(pamh,&userName,NULL); + if (retval != PAM_SUCCESS) + return PAM_SERVICE_ERR; + } + + pw = getpwnam(userName); + if (!pw) + return PAM_AUTH_ERR; /* user doesn't exist */ + userShell = pw->pw_shell; + + if(stat(SHELL_FILE,&sb)) { + _pam_log(LOG_ERR, + "%s cannot be stat'd (it probably does not exist)", SHELL_FILE); + return PAM_AUTH_ERR; /* must have /etc/shells */ + } + + if((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { + _pam_log(LOG_ERR, + "%s is either world writable or not a normal file", SHELL_FILE); + return PAM_AUTH_ERR; + } + + shellFile = fopen(SHELL_FILE,"r"); + if(shellFile == NULL) { /* Check that we opened it successfully */ + _pam_log(LOG_ERR, + "Error opening %s", SHELL_FILE); + return PAM_SERVICE_ERR; + } + /* There should be no more errors from here on */ + retval=PAM_AUTH_ERR; + /* This loop assumes that PAM_SUCCESS == 0 + and PAM_AUTH_ERR != 0 */ + while((fgets(shellFileLine,255,shellFile) != NULL) + && retval) { + if (shellFileLine[strlen(shellFileLine) - 1] == '\n') + shellFileLine[strlen(shellFileLine) - 1] = '\0'; + retval = strcmp(shellFileLine, userShell); + } + fclose(shellFile); + if(retval) + retval = PAM_AUTH_ERR; + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_shells_modstruct = { + "pam_shells", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_stress/Makefile b/Linux-PAM/modules/pam_stress/Makefile new file mode 100644 index 00000000..15a891c0 --- /dev/null +++ b/Linux-PAM/modules/pam_stress/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_stress + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_stress/README b/Linux-PAM/modules/pam_stress/README new file mode 100644 index 00000000..7a88f12d --- /dev/null +++ b/Linux-PAM/modules/pam_stress/README @@ -0,0 +1,66 @@ +# +# $Id: README,v 1.1.1.1 2001/04/29 04:17:34 hartmans Exp $ +# +# This describes the behavior of this module with respect to the +# /etc/pam.conf file. +# +# writen by Andrew Morgan <morgan@parc.power.net> +# + +This module recognizes the following arguments. + +debug put lots of information in syslog. + *NOTE* this option writes passwords to syslog, so + don't use anything sensitive when testing. + +no_warn don't give warnings about things (otherwise warnings are issued + via the conversation function) + +use_first_pass don't prompt for a password, for pam_sm_authentication + function just use item PAM_AUTHTOK. + +try_first_pass don't prompt for a password unless there has been no + previous authentication token (item PAM_AUTHTOK is NULL) + +rootok This is intended for the pam_sm_chauthtok function and + it instructs this function to permit root to change + the user's password without entering the old password. + +The following arguments are acted on by the module. They are intended +to make the module give the impression of failing as a fully +functioning module might. + +expired an argument intended for the account and chauthtok module + parts. It instructs the module to act as if the user's + password has expired + +fail_1 this instructs the module to make its first function fail. + +fail_2 this instructs the module to make its second function (if there + is one) fail. + + The function break up is indicated in the Module + Developers' Guide. Listed here it is: + + service function 1 function 2 + ------- ---------- ---------- + auth pam_sm_authenticate pam_sm_setcred + password pam_sm_chauthtok + session pam_sm_open_session pam_sm_close_session + account pam_sm_acct_mgmt + +prelim for pam_sm_chauthtok, means fail on PAM_PRELIM_CHECK. + +required for pam_sm_chauthtok, means fail if the user hasn't already + been authenticated by this module. (See stress_new_pwd data + item below.) + +# +# data strings that this module uses are the following: +# + +data name value(s) Comments +--------- -------- -------- +stress_new_pwd yes tells pam_sm_chauthtok that + pam_sm_acct_mgmt says we need a new + password diff --git a/Linux-PAM/modules/pam_stress/pam_stress.c b/Linux-PAM/modules/pam_stress/pam_stress.c new file mode 100644 index 00000000..8bc85f5d --- /dev/null +++ b/Linux-PAM/modules/pam_stress/pam_stress.c @@ -0,0 +1,565 @@ +/* pam_stress module */ + +/* $Id: pam_stress.c,v 1.1.1.1 2001/04/29 04:17:34 hartmans Exp $ + * + * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12 + */ + +#include <security/_pam_aconf.h> + +#include <stdlib.h> +#include <stdio.h> + +#define __USE_BSD +#include <syslog.h> + +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +static char *_strdup(const char *x) +{ + char *new; + new = malloc(strlen(x)+1); + strcpy(new,x); + return new; +} + +/* log errors */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* ---------- */ + +/* an internal function to turn all possible test arguments into bits + of a ctrl number */ + +/* generic options */ + +#define PAM_ST_DEBUG 01 +#define PAM_ST_NO_WARN 02 +#define PAM_ST_USE_PASS1 04 +#define PAM_ST_TRY_PASS1 010 +#define PAM_ST_ROOTOK 020 + +/* simulation options */ + +#define PAM_ST_EXPIRED 040 +#define PAM_ST_FAIL_1 0100 +#define PAM_ST_FAIL_2 0200 +#define PAM_ST_PRELIM 0400 +#define PAM_ST_REQUIRE_PWD 01000 + +/* some syslogging */ + +static void _pam_report(int ctrl, const char *name, int flags, + int argc, const char **argv) +{ + if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG, "CALLED: %s", name); + _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags, + (flags & PAM_SILENT) ? " (silent)":""); + _pam_log(LOG_DEBUG, "CTRL = 0%o",ctrl); + _pam_log(LOG_DEBUG, "ARGV :"); + while (argc--) { + _pam_log(LOG_DEBUG, " \"%s\"", *argv++); + } + } +} + +static int _pam_parse(int argc, const char **argv) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_ST_DEBUG; + else if (!strcmp(*argv,"no_warn")) + ctrl |= PAM_ST_NO_WARN; + else if (!strcmp(*argv,"use_first_pass")) + ctrl |= PAM_ST_USE_PASS1; + else if (!strcmp(*argv,"try_first_pass")) + ctrl |= PAM_ST_TRY_PASS1; + else if (!strcmp(*argv,"rootok")) + ctrl |= PAM_ST_ROOTOK; + + /* simulation options */ + + else if (!strcmp(*argv,"expired")) /* signal password needs + renewal */ + ctrl |= PAM_ST_EXPIRED; + else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */ + ctrl |= PAM_ST_FAIL_1; + else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */ + ctrl |= PAM_ST_FAIL_2; + else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred + to fail on first call */ + ctrl |= PAM_ST_PRELIM; + else if (!strcmp(*argv,"required")) /* module is fussy about the + user being authenticated */ + ctrl |= PAM_ST_REQUIRE_PWD; + + else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + +static int converse(pam_handle_t *pamh, int nargs + , struct pam_message **message + , struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv)) + == PAM_SUCCESS) { + retval = conv->conv(nargs, (const struct pam_message **) message + , response, conv->appdata_ptr); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval); + _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval)); + } + } else { + _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv"); + } + + return retval; +} + +/* authentication management functions */ + +static int stress_get_password(pam_handle_t *pamh, int flags + , int ctrl, char **password) +{ + char *pass; + + if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1)) + && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass) + == PAM_SUCCESS) + && (pass != NULL) ) { + pass = _strdup(pass); + } else if ((ctrl & PAM_ST_USE_PASS1)) { + _pam_log(LOG_WARNING, "pam_stress: no forwarded password"); + return PAM_PERM_DENIED; + } else { /* we will have to get one */ + struct pam_message msg[1],*pmsg[1]; + struct pam_response *resp; + int retval; + + /* set up conversation call */ + + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = "STRESS Password: "; + resp = NULL; + + if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) { + return retval; + } + + if (resp) { + if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) { + _pam_log(LOG_DEBUG, + "pam_sm_authenticate: NULL authtok given"); + } + if ((flags & PAM_DISALLOW_NULL_AUTHTOK) + && resp[0].resp == NULL) { + free(resp); + return PAM_AUTH_ERR; + } + + pass = resp[0].resp; /* remember this! */ + + resp[0].resp = NULL; + } else if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported"); + _pam_log(LOG_DEBUG,"getting password, but NULL returned!?"); + return PAM_CONV_ERR; + } + free(resp); + } + + *password = pass; /* this *MUST* be free()'d by this module */ + + return PAM_SUCCESS; +} + +/* function to clean up data items */ + +static void wipe_up(pam_handle_t *pamh, void *data, int error) +{ + free(data); +} + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + const char *username; + int retval=PAM_SUCCESS; + char *pass; + int ctrl; + + D(("called.")); + + ctrl = _pam_parse(argc,argv); + _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv); + + /* try to get the username */ + + retval = pam_get_user(pamh, &username, "username: "); + if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) { + _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username); + } else if (retval != PAM_SUCCESS) { + _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username"); + return retval; + } + + /* now get the password */ + + retval = stress_get_password(pamh,flags,ctrl,&pass); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_WARNING, "pam_sm_authenticate: " + "failed to get a password"); + return retval; + } + + /* try to set password item */ + + retval = pam_set_item(pamh,PAM_AUTHTOK,pass); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_WARNING, "pam_sm_authenticate: " + "failed to store new password"); + _pam_overwrite(pass); + free(pass); + return retval; + } + + /* clean up local copy of password */ + + _pam_overwrite(pass); + free(pass); + pass = NULL; + + /* if we are debugging then we print the password */ + + if (ctrl & PAM_ST_DEBUG) { + (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass); + _pam_log(LOG_DEBUG, + "pam_st_authenticate: password entered is: [%s]\n",pass); + pass = NULL; + } + + /* if we signal a fail for this function then fail */ + + if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS) + return PAM_PERM_DENIED; + + return retval; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int ctrl = _pam_parse(argc,argv); + + D(("called. [post parsing]")); + + _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv); + + if (ctrl & PAM_ST_FAIL_2) + return PAM_CRED_ERR; + + return PAM_SUCCESS; +} + +/* account management functions */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int ctrl = _pam_parse(argc,argv); + + D(("called. [post parsing]")); + + _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv); + + if (ctrl & PAM_ST_FAIL_1) + return PAM_PERM_DENIED; + else if (ctrl & PAM_ST_EXPIRED) { + void *text = malloc(sizeof("yes")+1); + strcpy(text,"yes"); + pam_set_data(pamh,"stress_new_pwd",text,wipe_up); + if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password"); + } + return PAM_NEW_AUTHTOK_REQD; + } + + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + char *username,*service; + int ctrl = _pam_parse(argc,argv); + + D(("called. [post parsing]")); + + _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv); + + if ((pam_get_item(pamh, PAM_USER, (const void **) &username) + != PAM_SUCCESS) + || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service) + != PAM_SUCCESS)) { + _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?"); + return PAM_SESSION_ERR; + } + + _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]" + , service, username); + + if (ctrl & PAM_ST_FAIL_1) + return PAM_SESSION_ERR; + + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + const char *username,*service; + int ctrl = _pam_parse(argc,argv); + + D(("called. [post parsing]")); + + _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv); + + if ((pam_get_item(pamh, PAM_USER, (const void **)&username) + != PAM_SUCCESS) + || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) + != PAM_SUCCESS)) { + _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?"); + return PAM_SESSION_ERR; + } + + _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]" + , service, username); + + if (ctrl & PAM_ST_FAIL_2) + return PAM_SESSION_ERR; + + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval; + int ctrl = _pam_parse(argc,argv); + + D(("called. [post parsing]")); + + _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv); + + /* this function should be called twice by the Linux-PAM library */ + + if (flags & PAM_PRELIM_CHECK) { /* first call */ + if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check"); + } + if (ctrl & PAM_ST_PRELIM) + return PAM_TRY_AGAIN; + + return PAM_SUCCESS; + } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */ + struct pam_message msg[3],*pmsg[3]; + struct pam_response *resp; + const char *text; + char *txt=NULL; + int i; + + if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password"); + } + + if (ctrl & PAM_ST_FAIL_1) + return PAM_AUTHTOK_LOCK_BUSY; + + if ( !(ctrl && PAM_ST_EXPIRED) + && (flags & PAM_CHANGE_EXPIRED_AUTHTOK) + && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text) + != PAM_SUCCESS || strcmp(text,"yes"))) { + return PAM_SUCCESS; /* the token has not expired */ + } + + /* the password should be changed */ + + if ((ctrl & PAM_ST_REQUIRE_PWD) + && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK)) + ) { /* first get old one? */ + char *pass; + + if (ctrl & PAM_ST_DEBUG) { + _pam_log(LOG_DEBUG + ,"pam_sm_chauthtok: getting old password"); + } + retval = stress_get_password(pamh,flags,ctrl,&pass); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_DEBUG + ,"pam_sm_chauthtok: no password obtained"); + return retval; + } + retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_DEBUG + ,"pam_sm_chauthtok: could not set OLDAUTHTOK"); + _pam_overwrite(pass); + free(pass); + return retval; + } + _pam_overwrite(pass); + free(pass); + } + + /* set up for conversation */ + + if (!(flags & PAM_SILENT)) { + char *username; + + if ( pam_get_item(pamh, PAM_USER, (const void **)&username) + || username == NULL ) { + _pam_log(LOG_ERR,"no username set"); + return PAM_USER_UNKNOWN; + } + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; +#define _LOCAL_STRESS_COMMENT "Changing STRESS password for " + txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT) + +strlen(username)+1); + strcpy(txt, _LOCAL_STRESS_COMMENT); +#undef _LOCAL_STRESS_COMMENT + strcat(txt, username); + msg[0].msg = txt; + i = 1; + } else { + i = 0; + } + + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = "Enter new STRESS password: "; + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = "Retype new STRESS password: "; + resp = NULL; + + retval = converse(pamh,i,pmsg,&resp); + if (txt) { + free(txt); + txt = NULL; /* clean up */ + } + if (retval != PAM_SUCCESS) { + return retval; + } + + if (resp == NULL) { + _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv"); + return PAM_CONV_ERR; + } + + /* store the password */ + + if (resp[i-2].resp && resp[i-1].resp) { + if (strcmp(resp[i-2].resp,resp[i-1].resp)) { + /* passwords are not the same; forget and return error */ + + _pam_drop_reply(resp, i); + + if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) { + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_ERROR_MSG; + msg[0].msg = "Verification mis-typed; " + "password unchaged"; + resp = NULL; + (void) converse(pamh,1,pmsg,&resp); + if (resp) { + _pam_drop_reply(resp, 1); + } + } + return PAM_AUTHTOK_ERR; + } + + if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text) + == PAM_SUCCESS) { + (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text); + text = NULL; + } + (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp); + } else { + _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp"); + retval = PAM_SYSTEM_ERR; + } + + _pam_drop_reply(resp, i); /* clean up the passwords */ + } else { + _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error"); + return PAM_SYSTEM_ERR; + } + + return retval; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_stress_modstruct = { + "pam_stress", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; + +#endif diff --git a/Linux-PAM/modules/pam_tally/Makefile b/Linux-PAM/modules/pam_tally/Makefile new file mode 100644 index 00000000..d173b080 --- /dev/null +++ b/Linux-PAM/modules/pam_tally/Makefile @@ -0,0 +1,103 @@ +# +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:58 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module and +# application for Linux-PAM. You should not modify this Makefile +# (unless you know what you are doing!). +# +# + +include ../../Make.Rules + +TITLE=pam_tally + +# +## Additional rules for making (and moving) the application added. +## Assuming that all modules' applications are called $TITLE +# + +LIBSRC = $(TITLE).c +LIBOBJ = $(TITLE).o +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +APPSRC = $(TITLE)_app.c +APPOBJ = $(TITLE)_app.o +APPOBJD = $(addprefix dynamic/,$(APPOBJ)) +APPOBJS = $(addprefix static/,$(APPOBJ)) + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + + +ifdef DYNAMIC +LIBSHARED = $(TITLE).so +endif + +ifdef STATIC +LIBSTATIC = lib$(TITLE).o +endif + +APPLICATION = $(TITLE) +APPMODE = 755 + +####################### don't edit below ####################### + +all: dirs $(LIBSHARED) $(LIBSTATIC) register $(APPLICATION) + +dirs: +ifdef DYNAMIC + $(MKDIR) ./dynamic +endif +ifdef STATIC + $(MKDIR) ./static +endif + +register: +ifdef STATIC + ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) +endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) + +$(APPLICATION): $(APPOBJD) $(TITLE).c + $(CC) $(CFLAGS) -o $@ $(APPOBJD) $(LOADLIBES) + +endif + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) + +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) + +$(APPLICATION): $(APPOBJS) $(TITLE).c + $(CC) $(CFLAGS) -o $@ $(APPOBJS) $(LOADLIBES) +endif + +install: all + $(MKDIR) $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif + $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) + $(INSTALL) -m $(APPMODE) $(APPLICATION) $(FAKEROOT)$(SUPLEMENTED) + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so + rm -f $(FAKEROOT)$(SUPLEMENTED)/$(TITLE) + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) $(APPOBJD) $(APPOBJS) core *~ + rm -f *.a *.o *.so *.bak dynamic/* static/* $(APPLICATION) + rm -rf dynamic static + +.c.o: + $(CC) $(CFLAGS) -c $< diff --git a/Linux-PAM/modules/pam_tally/README b/Linux-PAM/modules/pam_tally/README new file mode 100644 index 00000000..4c421648 --- /dev/null +++ b/Linux-PAM/modules/pam_tally/README @@ -0,0 +1,95 @@ +SUMMARY: + pam_tally: + + Maintains a count of attempted accesses, can reset count on success, + can deny access if too many attempts fail. + + Options: + + * onerr=[succeed|fail] (if something weird happens + such as unable to open the file, what to do?) + * file=/where/to/keep/counts (default /var/log/faillog) + + (auth) + Authentication phase increments attempted login counter. + * no_magic_root (root DOES increment counter. Use for + daemon-based stuff, like telnet/rsh/login) + + (account) + Account phase can deny access and/or reset attempts counter. + * deny=n (deny access if tally for this user exceeds n; + The presence of deny=n changes the default for + reset/no_reset to reset, unless the user trying to + gain access is root and the no_magic_root option + has NOT been specified.) + + * no_magic_root (access attempts by root DON'T ignore deny. + Use this for daemon-based stuff, like telnet/rsh/login) + * even_deny_root_account (Root can become unavailable. BEWARE. + Note that magic root trying to gain root bypasses this, + but normal users can be locked out.) + + * reset (reset count to 0 on successful entry, even for + magic root) + * no_reset (don't reset count on successful entry) + This is the default unless deny exists and the + user attempting access is NOT magic root. + + * per_user (If /var/log/faillog contains a non-zero + .fail_max field for this user then use it + instead of deny=n parameter) + + * no_lock_time (Don't use .fail_locktime filed in + /var/log/faillog for this user) + + Also checks to make sure that the counts file is a plain + file and not world writable. + + - Tim Baverstock <warwick@sable.demon.co.uk>, v0.1 5 March 1997 + +LONGER: + +pam_tally comes in two parts: pam_tally.so and pam_tally. + +pam_tally.so sits in a pam config file, in the auth and account sections. + +In the auth section, it increments a per-uid counter for each attempted +login, in the account section, it denies access if attempted logins +exceed some threashold and/or resets that counter to zero on successful +login. + +Root is treated specially: + +1. When a process already running as root tries to access some service, the +access is `magic', and bypasses pam_tally's checks: handy for `su'ing from +root into an account otherwise blocked. However, for services like telnet or +login which always effectively run from the root account, root (ie everyone) +shouldn't be granted this magic status, and the flag `no_magic_root' should +be set in this situation, as noted in the summary above. [This option may +be obsolete, with `sufficient root' processing.] + +2. Normally, failed attempts to access root will NOT cause the root +account to become blocked, to prevent denial-of-service: if your users aren't +given shell accounts and root may only login via `su' or at the machine +console (not telnet/rsh, etc), this is safe. If you really want root to be +blocked for some given service, use even_deny_root_account. + +pam_tally is an (optional) application which can be used to interrogate and +manipulate the counter file. It can display users' counts, set individual +counts, or clear all counts. Setting artificially high counts may be useful +for blocking users without changing their passwords. I found it useful to +clear all counts every midnight from a cron.. + +The counts file is organised as a binary-word array, indexed by uid. You +can probably make sense of it with `od', if you don't want to use the +supplied application. + +BUGS: + +pam_tally is very dependant on getpw*(): a database of usernames +would be much more flexible. + +The (4.0 Redhat) utilities seem to do funny things with uid, and I'm +not wholly sure I understood what I should have been doing anyway so +the `keep a count of current logins' bit has been #ifdef'd out and you +can only reset the counter on successful authentication, for now. diff --git a/Linux-PAM/modules/pam_tally/faillog.h b/Linux-PAM/modules/pam_tally/faillog.h new file mode 100644 index 00000000..fa9c414f --- /dev/null +++ b/Linux-PAM/modules/pam_tally/faillog.h @@ -0,0 +1,55 @@ +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * faillog.h - login failure logging file format + * + * $Id: faillog.h,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ + * + * The login failure file is maintained by login(1) and faillog(8) + * Each record in the file represents a separate UID and the file + * is indexed in that fashion. + */ + +#ifndef _FAILLOG_H +#define _FAILLOG_H + +struct faillog { + short fail_cnt; /* failures since last success */ + short fail_max; /* failures before turning account off */ + char fail_line[12]; /* last failure occured here */ + time_t fail_time; /* last failure occured then */ + /* + * If nonzero, the account will be re-enabled if there are no + * failures for fail_locktime seconds since last failure. + */ + long fail_locktime; +}; + +#endif diff --git a/Linux-PAM/modules/pam_tally/pam_tally.c b/Linux-PAM/modules/pam_tally/pam_tally.c new file mode 100644 index 00000000..a2fed80b --- /dev/null +++ b/Linux-PAM/modules/pam_tally/pam_tally.c @@ -0,0 +1,735 @@ +/* + * pam_tally.c + * + * $Id: pam_tally.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $ + */ + + +/* By Tim Baverstock <warwick@mmm.co.uk>, Multi Media Machine Ltd. + * 5 March 1997 + * + * Stuff stolen from pam_rootok and pam_listfile + */ + +#include <security/_pam_aconf.h> + +#if defined(MAIN) && defined(MEMORY_DEBUG) +# undef exit +#endif /* defined(MAIN) && defined(MEMORY_DEBUG) */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdlib.h> +#include <syslog.h> +#include <pwd.h> +#include <time.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include "faillog.h" + +#ifndef TRUE +#define TRUE 1L +#define FALSE 0L +#endif + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +/* #define PAM_SM_SESSION */ +/* #define PAM_SM_PASSWORD */ + +#include <security/pam_modules.h> + +/*---------------------------------------------------------------------*/ + +#define DEFAULT_LOGFILE "/var/log/faillog" +#define MODULE_NAME "pam_tally" + +enum TALLY_RESET { + TALLY_RESET_DEFAULT, + TALLY_RESET_RESET, + TALLY_RESET_NO_RESET +}; + +#define tally_t unsigned short int +#define TALLY_FMT "%hu" +#define TALLY_HI ((tally_t)~0L) + +#define UID_FMT "%hu" + +#ifndef FILENAME_MAX +# define FILENAME_MAX MAXPATHLEN +#endif + +struct fail_s { + struct faillog fs_faillog; +#ifndef MAIN + time_t fs_fail_time; +#endif /* ndef MAIN */ +}; + +/*---------------------------------------------------------------------*/ + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + va_start(args, format); + +#ifdef MAIN + vfprintf(stderr,format,args); + fprintf(stderr,"\n"); +#else + openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + closelog(); +#endif + va_end(args); +} + +/*---------------------------------------------------------------------*/ + +/* --- Support function: get uid (and optionally username) from PAM or + cline_user --- */ + +#ifdef MAIN +static char *cline_user=0; /* cline_user is used in the administration prog */ +#endif + +static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) + { + const char *user; + struct passwd *pw; + +#ifdef MAIN + user = cline_user; +#else + pam_get_user( pamh, &user, NULL ); +#endif + + if ( !user || !*user ) { + _pam_log(LOG_ERR, MODULE_NAME ": pam_get_uid; user?"); + return PAM_AUTH_ERR; + } + + if ( ! ( pw = getpwnam( user ) ) ) { + _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user %s",user); + return PAM_USER_UNKNOWN; + } + + if ( uid ) *uid = pw->pw_uid; + if ( userp ) *userp = user; + return PAM_SUCCESS; + } + +/*---------------------------------------------------------------------*/ + +/* --- Support function: open/create tallyfile and return tally for uid --- */ + +/* If on entry *tally==TALLY_HI, tallyfile is opened READONLY */ +/* Otherwise, if on entry tallyfile doesn't exist, creation is attempted. */ + +static int get_tally( tally_t *tally, + uid_t uid, + const char *filename, + FILE **TALLY, + struct fail_s *fsp) + { + struct stat fileinfo; + int lstat_ret = lstat(filename,&fileinfo); + + if ( lstat_ret && *tally!=TALLY_HI ) { + int oldmask = umask(077); + *TALLY=fopen(filename, "a"); + /* Create file, or append-open in pathological case. */ + umask(oldmask); + if ( !*TALLY ) { + _pam_log(LOG_ALERT, "Couldn't create %s",filename); + return PAM_AUTH_ERR; + } + lstat_ret = fstat(fileno(*TALLY),&fileinfo); + fclose(*TALLY); + } + + if ( lstat_ret ) { + _pam_log(LOG_ALERT, "Couldn't stat %s",filename); + return PAM_AUTH_ERR; + } + + if((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) { + /* If the file is world writable or is not a + normal file, return error */ + _pam_log(LOG_ALERT, + "%s is either world writable or not a normal file", + filename); + return PAM_AUTH_ERR; + } + + if ( ! ( *TALLY = fopen(filename,(*tally!=TALLY_HI)?"r+":"r") ) ) { + _pam_log(LOG_ALERT, "Error opening %s for update", filename); + +/* Discovering why account service fails: e/uid are target user. + * + * perror(MODULE_NAME); + * fprintf(stderr,"uid %d euid %d\n",getuid(), geteuid()); + */ + return PAM_AUTH_ERR; + } + + if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) { + _pam_log(LOG_ALERT, "fseek failed %s", filename); + return PAM_AUTH_ERR; + } + + if ( fileinfo.st_size <= uid * sizeof(struct faillog) ) { + + memset(fsp, 0, sizeof(struct faillog)); + *tally=0; + fsp->fs_faillog.fail_time = time(NULL); + + } else if (( fread((char *) &fsp->fs_faillog, + sizeof(struct faillog), 1, *TALLY) )==0 ) { + + *tally=0; /* Assuming a gappy filesystem */ + + } else { + + *tally = fsp->fs_faillog.fail_cnt; + + } + + return PAM_SUCCESS; + } + +/*---------------------------------------------------------------------*/ + +/* --- Support function: update and close tallyfile with tally!=TALLY_HI --- */ + +static int set_tally( tally_t tally, + uid_t uid, + const char *filename, + FILE **TALLY, + struct fail_s *fsp) + { + if ( tally!=TALLY_HI ) + { + if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) { + _pam_log(LOG_ALERT, "fseek failed %s", filename); + return PAM_AUTH_ERR; + } + fsp->fs_faillog.fail_cnt = tally; + if (fwrite((char *) &fsp->fs_faillog, + sizeof(struct faillog), 1, *TALLY)==0 ) { + _pam_log(LOG_ALERT, "tally update (fwrite) failed.", filename); + return PAM_AUTH_ERR; + } + } + + if ( fclose(*TALLY) ) { + _pam_log(LOG_ALERT, "tally update (fclose) failed.", filename); + return PAM_AUTH_ERR; + } + *TALLY=NULL; + return PAM_SUCCESS; + } + +/*---------------------------------------------------------------------*/ + +/* --- PAM bits --- */ + +#ifndef MAIN + +#define PAM_FUNCTION(name) \ + PAM_EXTERN int name (pam_handle_t *pamh,int flags,int argc,const char **argv) + +#define RETURN_ERROR(i) return ((fail_on_error)?(i):(PAM_SUCCESS)) + +/*---------------------------------------------------------------------*/ + +/* --- tally bump function: bump tally for uid by (signed) inc --- */ + +static int tally_bump (int inc, + pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { + uid_t uid; + + int + fail_on_error = FALSE; + tally_t + tally = 0; /* !TALLY_HI --> Log opened for update */ + + char + no_magic_root = FALSE; + + char + filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; + + /* Should probably decode the parameters before anything else. */ + + { + for ( ; argc-- > 0; ++argv ) { + + /* generic options.. um, ignored. :] */ + + if ( ! strcmp( *argv, "no_magic_root" ) ) { + no_magic_root = TRUE; + } + else if ( ! strncmp( *argv, "file=", 5 ) ) { + char const + *from = (*argv)+5; + char + *to = filename; + if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { + _pam_log(LOG_ERR, + MODULE_NAME ": filename not /rooted or too long; ", + *argv); + RETURN_ERROR( PAM_AUTH_ERR ); + } + while ( ( *to++ = *from++ ) ); + } + else if ( ! strcmp( *argv, "onerr=fail" ) ) { + fail_on_error=TRUE; + } + else if ( ! strcmp( *argv, "onerr=succeed" ) ) { + fail_on_error=FALSE; + } + else { + _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); + } + } /* for() */ + } + + { + FILE + *TALLY = NULL; + const char + *user = NULL, + *remote_host = NULL, + *cur_tty = NULL; + struct fail_s fs, *fsp = &fs; + + int i=pam_get_uid(pamh, &uid, &user); + if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); + + i=get_tally( &tally, uid, filename, &TALLY, fsp ); + + /* to remember old fail time (for locktime) */ + fsp->fs_fail_time = fsp->fs_faillog.fail_time; + fsp->fs_faillog.fail_time = time(NULL); + (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); + if (!remote_host) { + + (void) pam_get_item(pamh, PAM_TTY, (const void **)&cur_tty); + if (!cur_tty) { + strncpy(fsp->fs_faillog.fail_line, "unknown", + sizeof(fsp->fs_faillog.fail_line) - 1); + fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; + } else { + strncpy(fsp->fs_faillog.fail_line, cur_tty, + sizeof(fsp->fs_faillog.fail_line)-1); + fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; + } + + } else { + strncpy(fsp->fs_faillog.fail_line, remote_host, + (size_t)sizeof(fsp->fs_faillog.fail_line)); + fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; + } + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + + if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + + tally+=inc; + + if ( tally==TALLY_HI ) { /* Overflow *and* underflow. :) */ + tally-=inc; + _pam_log(LOG_ALERT,"Tally %sflowed for user %s", + (inc<0)?"under":"over",user); + } + } + + i=set_tally( tally, uid, filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + } + + return PAM_SUCCESS; +} + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_AUTH + +PAM_FUNCTION( pam_sm_authenticate ) { + return tally_bump( 1, pamh, flags, argc, argv); +} + +/* --- Seems to need this function. Ho hum. --- */ + +PAM_FUNCTION( pam_sm_setcred ) { return PAM_SUCCESS; } + +#endif + +/*---------------------------------------------------------------------*/ + +/* --- session management functions (only) --- */ + +/* + * Unavailable until .so files can be suid + */ + +#ifdef PAM_SM_SESSION + +/* To maintain a balance-tally of successful login/outs */ + +PAM_FUNCTION( pam_sm_open_session ) { + return tally_bump( 1, pamh, flags, argc, argv); +} + +PAM_FUNCTION( pam_sm_close_session ) { + return tally_bump(-1, pamh, flags, argc, argv); +} + +#endif + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_AUTH + +/* To lock out a user with an unacceptably high tally */ + +PAM_FUNCTION( pam_sm_acct_mgmt ) { + uid_t + uid; + + int + fail_on_error = FALSE; + tally_t + deny = 0; + tally_t + tally = 0; /* !TALLY_HI --> Log opened for update */ + + char + no_magic_root = FALSE, + even_deny_root_account = FALSE; + char per_user = FALSE; /* if true then deny=.fail_max for user */ + char no_lock_time = FALSE; /* if true then don't use .fail_locktime */ + + const char + *user = NULL; + + enum TALLY_RESET + reset = TALLY_RESET_DEFAULT; + + char + filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; + + /* Should probably decode the parameters before anything else. */ + + { + for ( ; argc-- > 0; ++argv ) { + + /* generic options.. um, ignored. :] */ + + if ( ! strcmp( *argv, "no_magic_root" ) ) { + no_magic_root = TRUE; + } + else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { + even_deny_root_account = TRUE; + } + else if ( ! strcmp( *argv, "reset" ) ) { + reset = TALLY_RESET_RESET; + } + else if ( ! strcmp( *argv, "no_reset" ) ) { + reset = TALLY_RESET_NO_RESET; + } + else if ( ! strncmp( *argv, "file=", 5 ) ) { + char const + *from = (*argv)+5; + char + *to = filename; + if ( *from != '/' || strlen(from) > FILENAME_MAX-1 ) { + _pam_log(LOG_ERR, + MODULE_NAME ": filename not /rooted or too long; ", + *argv); + RETURN_ERROR( PAM_AUTH_ERR ); + } + while ( ( *to++ = *from++ ) ); + } + else if ( ! strncmp( *argv, "deny=", 5 ) ) { + if ( sscanf((*argv)+5,TALLY_FMT,&deny) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + RETURN_ERROR( PAM_AUTH_ERR ); + } + } + else if ( ! strcmp( *argv, "onerr=fail" ) ) { + fail_on_error=TRUE; + } + else if ( ! strcmp( *argv, "onerr=succeed" ) ) { + fail_on_error=FALSE; + } + else if ( ! strcmp( *argv, "per_user" ) ) + { + per_user = TRUE; + } + else if ( ! strcmp( *argv, "no_lock_time") ) + { + no_lock_time = TRUE; + } + else { + _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); + } + } /* for() */ + } + + { + struct fail_s fs, *fsp = &fs; + FILE *TALLY=0; + int i=pam_get_uid(pamh, &uid, &user); + if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); + + i=get_tally( &tally, uid, filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + + if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + + /* To deny or not to deny; that is the question */ + + /* if there's .fail_max entry and per_user=TRUE then deny=.fail_max */ + + if ( (fsp->fs_faillog.fail_max) && (per_user) ) { + deny = fsp->fs_faillog.fail_max; + } + if (fsp->fs_faillog.fail_locktime && fsp->fs_fail_time + && (!no_lock_time) ) + { + if ( (fsp->fs_faillog.fail_locktime + fsp->fs_fail_time) > time(NULL) ) + { + _pam_log(LOG_NOTICE, + "user %s ("UID_FMT") has time limit [%lds left]" + " since last failure.", + user,uid, + fsp->fs_fail_time+fsp->fs_faillog.fail_locktime + -time(NULL)); + return PAM_AUTH_ERR; + } + } + if ( + ( deny != 0 ) && /* deny==0 means no deny */ + ( tally > deny ) && /* tally>deny means exceeded */ + ( even_deny_root_account || uid ) /* even_deny stops uid check */ + ) { + _pam_log(LOG_NOTICE,"user %s ("UID_FMT") tally "TALLY_FMT", deny "TALLY_FMT, + user, uid, tally, deny); + return PAM_AUTH_ERR; /* Only unconditional failure */ + } + + /* resets for explicit reset + * or by default if deny exists and not magic-root + */ + + if ( ( reset == TALLY_RESET_RESET ) || + ( reset == TALLY_RESET_DEFAULT && deny ) ) { tally=0; } + } + else /* is magic root */ { + + /* Magic root skips deny test... */ + + /* Magic root only resets on explicit reset, regardless of deny */ + + if ( reset == TALLY_RESET_RESET ) { tally=0; } + } + if (tally == 0) + { + fsp->fs_faillog.fail_time = (time_t) 0; + strcpy(fsp->fs_faillog.fail_line, ""); + } + i=set_tally( tally, uid, filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + } + + return PAM_SUCCESS; +} + +#endif /* #ifdef PAM_SM_AUTH */ + +/*-----------------------------------------------------------------------*/ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_tally_modstruct = { + MODULE_NAME, +#ifdef PAM_SM_AUTH + pam_sm_authenticate, + pam_sm_setcred, +#else + NULL, + NULL, +#endif +#ifdef PAM_SM_ACCOUNT + pam_sm_acct_mgmt, +#else + NULL, +#endif +#ifdef PAM_SM_SESSION + pam_sm_open_session, + pam_sm_close_session, +#else + NULL, + NULL, +#endif +#ifdef PAM_SM_PASSWORD + pam_sm_chauthtok, +#else + NULL, +#endif +}; + +#endif /* #ifdef PAM_STATIC */ + +/*-----------------------------------------------------------------------*/ + +#else /* #ifndef MAIN */ + +static const char *cline_filename = DEFAULT_LOGFILE; +static tally_t cline_reset = TALLY_HI; /* Default is `interrogate only' */ +static int cline_quiet = 0; + +/* + * Not going to link with pamlib just for these.. :) + */ + +static const char * pam_errors( int i ) { + switch (i) { + case PAM_AUTH_ERR: return "Authentication error"; + case PAM_SERVICE_ERR: return "Service error"; + case PAM_USER_UNKNOWN: return "Unknown user"; + default: return "Unknown error"; + } +} + +static int getopts( int argc, char **argv ) { + const char *pname = *argv; + for ( ; *argv ; (void)(*argv && ++argv) ) { + if ( !strcmp (*argv,"--file") ) cline_filename=*++argv; + else if ( !strncmp(*argv,"--file=",7) ) cline_filename=*argv+7; + else if ( !strcmp (*argv,"--user") ) cline_user=*++argv; + else if ( !strncmp(*argv,"--user=",7) ) cline_user=*argv+7; + else if ( !strcmp (*argv,"--reset") ) cline_reset=0; + else if ( !strncmp(*argv,"--reset=",8)) { + if ( sscanf(*argv+8,TALLY_FMT,&cline_reset) != 1 ) + fprintf(stderr,"%s: Bad number given to --reset=\n",pname), exit(0); + } + else if ( !strcmp (*argv,"--quiet") ) cline_quiet=1; + else { + fprintf(stderr,"%s: Unrecognised option %s\n",pname,*argv); + return FALSE; + } + } + return TRUE; +} + +int main ( int argc, char **argv ) { + + struct fail_s fs, *fsp = &fs; + + if ( ! getopts( argc, argv+1 ) ) { + printf("%s: [--file rooted-filename] [--user username] " + "[--reset[=n]] [--quiet]\n", + *argv); + exit(0); + } + + umask(077); + + /* + * Major difference between individual user and all users: + * --user just handles one user, just like PAM. + * --user=* handles all users, sniffing cline_filename for nonzeros + */ + + if ( cline_user ) { + uid_t uid; + tally_t tally=cline_reset; + FILE *TALLY=0; + int i=pam_get_uid( NULL, &uid, NULL); + if ( i != PAM_SUCCESS ) { + fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); + exit(0); + } + + i=get_tally( &tally, uid, cline_filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { + if (TALLY) fclose(TALLY); + fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); + exit(0); + } + + if ( !cline_quiet ) + printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",cline_user,uid, + (cline_reset!=TALLY_HI)?"had":"has",tally); + + i=set_tally( cline_reset, uid, cline_filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { + if (TALLY) fclose(TALLY); + fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); + exit(0); + } + } + else /* !cline_user (ie, operate on all users) */ { + FILE *TALLY=fopen(cline_filename, "r"); + uid_t uid=0; + if ( !TALLY ) perror(*argv), exit(0); + + for ( ; !feof(TALLY); uid++ ) { + tally_t tally; + struct passwd *pw; + if ( ! fread((char *) &fsp->fs_faillog, + sizeof (struct faillog), 1, TALLY) + || ! fsp->fs_faillog.fail_cnt ) { + continue; + } + tally = fsp->fs_faillog.fail_cnt; + + if ( ( pw=getpwuid(uid) ) ) { + printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",pw->pw_name,uid, + (cline_reset!=TALLY_HI)?"had":"has",tally); + } + else { + printf("User [NONAME]\t("UID_FMT")\t%s "TALLY_FMT"\n",uid, + (cline_reset!=TALLY_HI)?"had":"has",tally); + } + } + fclose(TALLY); + if ( cline_reset!=0 && cline_reset!=TALLY_HI ) { + fprintf(stderr,"%s: Can't reset all users to non-zero\n",*argv); + } + else if ( !cline_reset ) { + TALLY=fopen(cline_filename, "w"); + if ( !TALLY ) perror(*argv), exit(0); + fclose(TALLY); + } + } + return 0; +} + + +#endif diff --git a/Linux-PAM/modules/pam_tally/pam_tally_app.c b/Linux-PAM/modules/pam_tally/pam_tally_app.c new file mode 100644 index 00000000..9e6e1faf --- /dev/null +++ b/Linux-PAM/modules/pam_tally/pam_tally_app.c @@ -0,0 +1,7 @@ +/* + # This seemed like such a good idea at the time. :) + */ + +#define MAIN +#include "pam_tally.c" + diff --git a/Linux-PAM/modules/pam_time/Makefile b/Linux-PAM/modules/pam_time/Makefile new file mode 100644 index 00000000..647d3081 --- /dev/null +++ b/Linux-PAM/modules/pam_time/Makefile @@ -0,0 +1,21 @@ +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_time +LOCAL_CONFILE=./time.conf +INSTALLED_CONFILE=$(SCONFIGD)/time.conf + +DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" +CFLAGS += $(DEFS) + +MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" +MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) +MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_time/README b/Linux-PAM/modules/pam_time/README new file mode 100644 index 00000000..4ef51531 --- /dev/null +++ b/Linux-PAM/modules/pam_time/README @@ -0,0 +1,30 @@ +$Id: README,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ + +This is a help file for the pam_time module. It explains the need for +pam_time and also the syntax of the /etc/security/time.conf file. +[a lot of the syntax is freely adapted from the porttime file of the +shadow suite.] + +1. Introduction +=============== + +It is desirable to restrict access to a system and or specific +applications at various times of the day and on specific days or over +various terminal lines. + +The pam_time module is intended to offer a configurable module that +satisfies this purpose, within the context of Linux-PAM. + +2. the /etc/security/time.conf file +=================================== + +This file is the configuration script for defining time/port access +control to the system/applications. + +Its syntax is described in the sample ./time.conf provided in this +directory. + +unrecognised rules are ignored (but an error is logged to syslog(3)) + +-------------------- +Bugs to Andrew <morgan@parc.power.net> or the list <pam-list@redhat.com> diff --git a/Linux-PAM/modules/pam_time/pam_time.c b/Linux-PAM/modules/pam_time/pam_time.c new file mode 100644 index 00000000..5757a557 --- /dev/null +++ b/Linux-PAM/modules/pam_time/pam_time.c @@ -0,0 +1,622 @@ +/* pam_time module */ + +/* + * $Id: pam_time.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/6/22 + * (File syntax and much other inspiration from the shadow package + * shadow-960129) + */ + +const static char rcsid[] = +"$Id: pam_time.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $;\n" +"\t\tVersion 0.22 for Linux-PAM\n" +"Copyright (C) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; + +#include <security/_pam_aconf.h> + +#include <sys/file.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <stdarg.h> +#include <time.h> +#include <syslog.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifdef DEFAULT_CONF_FILE +# define PAM_TIME_CONF DEFAULT_CONF_FILE /* from external define */ +#else +# define PAM_TIME_CONF "/etc/security/time.conf" +#endif +#define PAM_TIME_BUFLEN 1000 +#define FIELD_SEPARATOR ';' /* this is new as of .02 */ + +#ifdef TRUE +# undef TRUE +#endif +#ifdef FALSE +# undef FALSE +#endif + +typedef enum { FALSE, TRUE } boolean; +typedef enum { AND, OR } operator; + +/* + * here, we make definitions for the externally accessible functions + * in this file (these definitions are required for static modules + * but strongly encouraged generally) they are used to instruct the + * modules include file to define their prototypes. + */ + +#define PAM_SM_ACCOUNT + +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +/* --- static functions for checking whether the user should be let in --- */ + +static void _log_err(const char *format, ... ) +{ + va_list args; + + va_start(args, format); + openlog("pam_time", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(LOG_CRIT, format, args); + va_end(args); + closelog(); +} + +static void shift_bytes(char *mem, int from, int by) +{ + while (by-- > 0) { + *mem = mem[from]; + ++mem; + } +} + +static int read_field(int fd, char **buf, int *from, int *to) +{ + /* is buf set ? */ + + if (! *buf) { + *buf = (char *) malloc(PAM_TIME_BUFLEN); + if (! *buf) { + _log_err("out of memory"); + D(("no memory")); + return -1; + } + *from = *to = 0; + fd = open(PAM_TIME_CONF, O_RDONLY); + } + + /* do we have a file open ? return error */ + + if (fd < 0 && *to <= 0) { + _log_err( PAM_TIME_CONF " not opened"); + memset(*buf, 0, PAM_TIME_BUFLEN); + _pam_drop(*buf); + return -1; + } + + /* check if there was a newline last time */ + + if ((*to > *from) && (*to > 0) + && ((*buf)[*from] == '\0')) { /* previous line ended */ + (*from)++; + (*buf)[0] = '\0'; + return fd; + } + + /* ready for more data: first shift the buffer's remaining data */ + + *to -= *from; + shift_bytes(*buf, *from, *to); + *from = 0; + (*buf)[*to] = '\0'; + + while (fd >= 0 && *to < PAM_TIME_BUFLEN) { + int i; + + /* now try to fill the remainder of the buffer */ + + i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to); + if (i < 0) { + _log_err("error reading " PAM_TIME_CONF); + return -1; + } else if (!i) { + close(fd); + fd = -1; /* end of file reached */ + } else + *to += i; + + /* + * contract the buffer. Delete any comments, and replace all + * multiple spaces with single commas + */ + + i = 0; +#ifdef DEBUG_DUMP + D(("buffer=<%s>",*buf)); +#endif + while (i < *to) { + if ((*buf)[i] == ',') { + int j; + + for (j=++i; j<*to && (*buf)[j] == ','; ++j); + if (j!=i) { + shift_bytes(i + (*buf), j-i, (*to) - j); + *to -= j-i; + } + } + switch ((*buf)[i]) { + int j,c; + case '#': + for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); + if (j >= *to) { + (*buf)[*to = ++i] = '\0'; + } else if (c == '\n') { + shift_bytes(i + (*buf), j-i, (*to) - j); + *to -= j-i; + ++i; + } else { + _log_err("internal error in " __FILE__ + " at line %d", __LINE__ ); + return -1; + } + break; + case '\\': + if ((*buf)[i+1] == '\n') { + shift_bytes(i + *buf, 2, *to - (i+2)); + *to -= 2; + } else { + ++i; /* we don't escape non-newline characters */ + } + break; + case '!': + case ' ': + case '\t': + if ((*buf)[i] != '!') + (*buf)[i] = ','; + /* delete any trailing spaces */ + for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' + || c == '\t' ); ++j); + shift_bytes(i + *buf, j-i, (*to)-j ); + *to -= j-i; + break; + default: + ++i; + } + } + } + + (*buf)[*to] = '\0'; + + /* now return the next field (set the from/to markers) */ + { + int i; + + for (i=0; i<*to; ++i) { + switch ((*buf)[i]) { + case '#': + case '\n': /* end of the line/file */ + (*buf)[i] = '\0'; + *from = i; + return fd; + case FIELD_SEPARATOR: /* end of the field */ + (*buf)[i] = '\0'; + *from = ++i; + return fd; + } + } + *from = i; + (*buf)[*from] = '\0'; + } + + if (*to <= 0) { + D(("[end of text]")); + *buf = NULL; + } + + return fd; +} + +/* read a member from a field */ + +static int logic_member(const char *string, int *at) +{ + int len,c,to; + int done=0; + int token=0; + + len=0; + to=*at; + do { + c = string[to++]; + + switch (c) { + + case '\0': + --to; + done = 1; + break; + + case '&': + case '|': + case '!': + if (token) { + --to; + } + done = 1; + break; + + default: + if (isalpha(c) || c == '*' || isdigit(c) || c == '_' + || c == '-' || c == '.' || c == '/') { + token = 1; + } else if (token) { + --to; + done = 1; + } else { + ++*at; + } + } + } while (!done); + + return to - *at; +} + +typedef enum { VAL, OP } expect; + +static boolean logic_field(const void *me, const char *x, int rule, + boolean (*agrees)(const void *, const char * + , int, int)) +{ + boolean left=FALSE, right, not=FALSE; + operator oper=OR; + int at=0, l; + expect next=VAL; + + while ((l = logic_member(x,&at))) { + int c = x[at]; + + if (next == VAL) { + if (c == '!') + not = !not; + else if (isalpha(c) || c == '*') { + right = not ^ agrees(me, x+at, l, rule); + if (oper == AND) + left &= right; + else + left |= right; + next = OP; + } else { + _log_err("garbled syntax; expected name (rule #%d)", rule); + return FALSE; + } + } else { /* OP */ + switch (c) { + case '&': + oper = AND; + break; + case '|': + oper = OR; + break; + default: + _log_err("garbled syntax; expected & or | (rule #%d)" + , rule); + D(("%c at %d",c,at)); + return FALSE; + } + next = VAL; + } + at += l; + } + + return left; +} + +static boolean is_same(const void *A, const char *b, int len, int rule) +{ + int i; + const char *a; + + a = A; + for (i=0; len > 0; ++i, --len) { + if (b[i] != a[i]) { + if (b[i++] == '*') { + return (!--len || !strncmp(b+i,a+strlen(a)-len,len)); + } else + return FALSE; + } + } + return ( !len ); +} + +typedef struct { + int day; /* array of 7 bits, one set for today */ + int minute; /* integer, hour*100+minute for now */ +} TIME; + +struct day { + const char *d; + int bit; +} static const days[11] = { + { "su", 01 }, + { "mo", 02 }, + { "tu", 04 }, + { "we", 010 }, + { "th", 020 }, + { "fr", 040 }, + { "sa", 0100 }, + { "wk", 076 }, + { "wd", 0101 }, + { "al", 0177 }, + { NULL, 0 } +}; + +static TIME time_now(void) +{ + struct tm *local; + time_t the_time; + TIME this; + + the_time = time((time_t *)0); /* get the current time */ + local = localtime(&the_time); + this.day = days[local->tm_wday].bit; + this.minute = local->tm_hour*100 + local->tm_min; + + D(("day: 0%o, time: %.4d", this.day, this.minute)); + return this; +} + +/* take the current date and see if the range "date" passes it */ +static boolean check_time(const void *AT, const char *times, int len, int rule) +{ + boolean not,pass; + int marked_day, time_start, time_end; + const TIME *at; + int i,j=0; + + at = AT; + D(("chcking: 0%o/%.4d vs. %s", at->day, at->minute, times)); + + if (times == NULL) { + /* this should not happen */ + _log_err("internal error: " __FILE__ " line %d", __LINE__); + return FALSE; + } + + if (times[j] == '!') { + ++j; + not = TRUE; + } else { + not = FALSE; + } + + for (marked_day = 0; len > 0 && isalpha(times[j]); --len) { + int this_day=-1; + + D(("%c%c ?", times[j], times[j+1])); + for (i=0; days[i].d != NULL; ++i) { + if (tolower(times[j]) == days[i].d[0] + && tolower(times[j+1]) == days[i].d[1] ) { + this_day = days[i].bit; + break; + } + } + j += 2; + if (this_day == -1) { + _log_err("bad day specified (rule #%d)", rule); + return FALSE; + } + marked_day ^= this_day; + } + if (marked_day == 0) { + _log_err("no day specified"); + return FALSE; + } + D(("day range = 0%o", marked_day)); + + time_start = 0; + for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) { + time_start *= 10; + time_start += times[i+j]-'0'; /* is this portable? */ + } + j += i; + + if (times[j] == '-') { + time_end = 0; + for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) { + time_end *= 10; + time_end += times[i+j]-'0'; /* is this portable */ + } + j += i; + } else + time_end = -1; + + D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j])); + if (i != 5 || time_end == -1) { + _log_err("no/bad times specified (rule #%d)", rule); + return TRUE; + } + D(("times(%d to %d)", time_start,time_end)); + D(("marked_day = 0%o", marked_day)); + + /* compare with the actual time now */ + + pass = FALSE; + if (time_start < time_end) { /* start < end ? --> same day */ + if ((at->day & marked_day) && (at->minute >= time_start) + && (at->minute < time_end)) { + D(("time is listed")); + pass = TRUE; + } + } else { /* spans two days */ + if ((at->day & marked_day) && (at->minute >= time_start)) { + D(("caught on first day")); + pass = TRUE; + } else { + marked_day <<= 1; + marked_day |= (marked_day & 0200) ? 1:0; + D(("next day = 0%o", marked_day)); + if ((at->day & marked_day) && (at->minute <= time_end)) { + D(("caught on second day")); + pass = TRUE; + } + } + } + + return (not ^ pass); +} + +static int check_account(const char *service + , const char *tty, const char *user) +{ + int from=0,to=0,fd=-1; + char *buffer=NULL; + int count=0; + TIME here_and_now; + int retval=PAM_SUCCESS; + + here_and_now = time_now(); /* find current time */ + do { + boolean good=TRUE,intime; + + /* here we get the service name field */ + + fd = read_field(fd,&buffer,&from,&to); + + if (!buffer || !buffer[0]) { + /* empty line .. ? */ + continue; + } + ++count; + + good = logic_field(service, buffer, count, is_same); + D(("with service: %s", good ? "passes":"fails" )); + + /* here we get the terminal name field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_TIME_CONF "; no tty entry #%d", count); + continue; + } + good &= logic_field(tty, buffer, count, is_same); + D(("with tty: %s", good ? "passes":"fails" )); + + /* here we get the username field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_TIME_CONF "; no user entry #%d", count); + continue; + } + good &= logic_field(user, buffer, count, is_same); + D(("with user: %s", good ? "passes":"fails" )); + + /* here we get the time field */ + + fd = read_field(fd,&buffer,&from,&to); + if (!buffer || !buffer[0]) { + _log_err(PAM_TIME_CONF "; no time entry #%d", count); + continue; + } + + intime = logic_field(&here_and_now, buffer, count, check_time); + D(("with time: %s", intime ? "passes":"fails" )); + + fd = read_field(fd,&buffer,&from,&to); + if (buffer && buffer[0]) { + _log_err(PAM_TIME_CONF "; poorly terminated rule #%d", count); + continue; + } + + if (good && !intime) { + /* + * for security parse whole file.. also need to ensure + * that the buffer is free()'d and the file is closed. + */ + retval = PAM_PERM_DENIED; + } else { + D(("rule passed")); + } + } while (buffer); + + return retval; +} + +/* --- public account management functions --- */ + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + const char *service=NULL, *tty=NULL; + const char *user=NULL; + + /* set service name */ + + if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) + != PAM_SUCCESS || service == NULL) { + _log_err("cannot find the current service name"); + return PAM_ABORT; + } + + /* set username */ + + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL + || *user == '\0') { + _log_err("cannot determine the user's name"); + return PAM_USER_UNKNOWN; + } + + /* set tty name */ + + if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS + || tty == NULL) { + D(("PAM_TTY not set, probing stdin")); + tty = ttyname(STDIN_FILENO); + if (tty == NULL) { + _log_err("couldn't get the tty name"); + return PAM_ABORT; + } + if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { + _log_err("couldn't set tty name"); + return PAM_ABORT; + } + } + + if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */ + tty += 5; + } + + /* good, now we have the service name, the user and the terminal name */ + + D(("service=%s", service)); + D(("user=%s", user)); + D(("tty=%s", tty)); + + return check_account(service,tty,user); +} + +/* end of module definition */ + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_time_modstruct = { + "pam_time", + NULL, + NULL, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL +}; +#endif diff --git a/Linux-PAM/modules/pam_time/time.conf b/Linux-PAM/modules/pam_time/time.conf new file mode 100644 index 00000000..d2062fdb --- /dev/null +++ b/Linux-PAM/modules/pam_time/time.conf @@ -0,0 +1,64 @@ +# this is an example configuration file for the pam_time module. Its syntax +# was initially based heavily on that of the shadow package (shadow-960129). +# +# the syntax of the lines is as follows: +# +# services;ttys;users;times +# +# white space is ignored and lines maybe extended with '\\n' (escaped +# newlines). As should be clear from reading these comments, +# text following a '#' is ignored to the end of the line. +# +# the combination of individual users/terminals etc is a logic list +# namely individual tokens that are optionally prefixed with '!' (logical +# not) and separated with '&' (logical and) and '|' (logical or). +# +# services +# is a logic list of PAM service names that the rule applies to. +# +# ttys +# is a logic list of terminal names that this rule applies to. +# +# users +# is a logic list of users to whom this rule applies. +# +# NB. For these items the simple wildcard '*' may be used only once. +# +# times +# the format here is a logic list of day/time-range +# entries the days are specified by a sequence of two character +# entries, MoTuSa for example is Monday Tuesday and Saturday. Note +# that repeated days are unset MoMo = no day, and MoWk = all weekdays +# bar Monday. The two character combinations accepted are +# +# Mo Tu We Th Fr Sa Su Wk Wd Al +# +# the last two being week-end days and all 7 days of the week +# respectively. As a final example, AlFr means all days except Friday. +# +# each day/time-range can be prefixed with a '!' to indicate "anything +# but" +# +# The time-range part is two 24-hour times HHMM separated by a hyphen +# indicating the start and finish time (if the finish time is smaller +# than the start time it is deemed to apply on the following day). +# +# for a rule to be active, ALL of service+ttys+users must be satisfied +# by the applying process. +# + +# +# Here is a simple example: running blank on tty* (any ttyXXX device), +# the users 'you' and 'me' are denied service all of the time +# + +#blank;tty* & !ttyp*;you|me;!Al0000-2400 + +# Another silly example, user 'root' is denied xsh access +# from pseudo terminals at the weekend and on mondays. + +#xsh;ttyp*;root;!WdMo0000-2400 + +# +# End of example file. +# \ No newline at end of file diff --git a/Linux-PAM/modules/pam_unix/CHANGELOG b/Linux-PAM/modules/pam_unix/CHANGELOG new file mode 100644 index 00000000..206d30dd --- /dev/null +++ b/Linux-PAM/modules/pam_unix/CHANGELOG @@ -0,0 +1,55 @@ +$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ + +* Mon Aug 16 1999 Jan Rêkorajski <baggins@pld.org.pl> +- fixed reentrancy problems + +* Sun Jul 4 21:03:42 PDT 1999 + +- temporarily removed the crypt16 stuff. I'm really paranoid about + crypto stuff and exporting it, and there are a few too many 's-box' + references in the code for my liking.. + +* Wed Jun 30 1999 Steve Langasek <vorlon@netexpress.net> +- further NIS+ fixes + +* Sun Jun 27 1999 Steve Langasek <vorlon@netexpress.net> +- fix to uid-handling code for NIS+ + +* Sat Jun 26 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- merged MD5 fix and early failure syslog + by Andrey Vladimirovich Savochkin <saw@msu.ru> +- minor fixes +- added signal handler to unix_chkpwd + +* Fri Jun 25 1999 Stephen Langasek <vorlon@netexpress.net> +- reorganized the code to let it build as separate C files + +* Sun Jun 20 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- fixes in pam_unix_auth, it incorrectly saved and restored return + value when likeauth option was used + +* Tue Jun 15 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- added NIS+ support + +* Mon Jun 14 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- total rewrite based on pam_pwdb module, now there is ONE pam_unix.so + module, it accepts the same options as pam_pwdb - all of them correctly ;) + (pam_pwdb dosn't understand what DISALLOW_NULL_AUTHTOK means) + +* Tue Apr 20 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- Arghhh, pam_unix_passwd was not updating /etc/shadow when used with + pam_cracklib. + +* Mon Apr 19 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- added "remember=XXX" option that means 'remember XXX old passwords' + Old passwords are stored in /etc/security/opasswd, there can be + maximum of 400 passwords per user. + +* Sat Mar 27 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- added crypt16 to pam_unix_auth and pam_unix_passwd (check only, this algorithm + is too lame to use it in real life) + +* Sun Mar 21 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> +- pam_unix_auth now correctly behave when user has NULL AUTHTOK +- pam_unix_auth returns PAM_PERM_DENIED when seteuid fails + diff --git a/Linux-PAM/modules/pam_unix/Makefile b/Linux-PAM/modules/pam_unix/Makefile new file mode 100644 index 00000000..03374512 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/Makefile @@ -0,0 +1,167 @@ +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ +# +# This Makefile controls a build process of the pam_unix modules +# for Linux-PAM. You should not modify this Makefile. +# + +include ../../Make.Rules + +######################################################################## +# some options... uncomment to take effect +######################################################################## + +# Unless someone wants to work out how to make this work with the new +# autoconf stuff, you should use a separate module for this type of thing +# pam_cracklib perhaps..? +# do you want cracklib? +#ifeq ($(HAVE_CRACKLIB),yes) +#USE_CRACKLIB=-D"USE_CRACKLIB" +#endif + +# do you want to use lckpwdf? +ifeq ($(WITH_LCKPWDF),yes) +USE_LCKPWDF=-D"USE_LCKPWDF" +# do you need to include the locking functions in the source? +ifeq ($(HAVE_LCKPWDF),no) + NEED_LCKPWDF=-D"NEED_LCKPWDF" +endif +endif + +ifeq ($(HAVE_LIBNSL),yes) + LIBNSL = -lnsl +endif + +ifeq ($(HAVE_LIBCRYPT),yes) + LIBCRYPT=-lcrypt +endif + +CHKPWD=unix_chkpwd + +EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" + +######################################################################## + +CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) +LDLIBS = $(EXTRALS) + +ifdef USE_CRACKLIB +CRACKLIB = -lcrack +endif + + +LIBOBJ = pam_unix_auth.o pam_unix_acct.o pam_unix_sess.o pam_unix_passwd.o \ + support.o +LIBSRC = pam_unix_auth.c pam_unix_acct.c pam_unix_sess.c pam_unix_passwd.c \ + support.c +LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) +LIBOBJS = $(addprefix static/,$(LIBOBJ)) + +PLUS = md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o \ + yppasswd_xdr.o bigcrypt.o + +ifdef DYNAMIC +LIBSHARED = pam_unix.so +endif +ifdef STATIC +LIBSTATIC = libpam_unix.o +endif + + +########################### don't edit below ####################### + +all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o: %.c + $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +dummy: + @echo "**** This is not a top-level Makefile " + exit + +info: + @echo + @echo "*** Building pam-unix module of the framework..." + @echo + +dirs: +ifdef DYNAMIC + mkdir -p ./dynamic +endif +ifdef STATIC + mkdir -p ./static +endif + +register: +ifdef STATIC + ( cd .. ; ./register_static pam_unix_auth pam_unix/$(LIBSTATIC) ; \ + ./register_static pam_unix_acct "" ; \ + ./register_static pam_unix_session "" ; \ + ./register_static pam_unix_passwd "" ; \ + ) +endif + +ifdef DYNAMIC +$(LIBOBJD): $(LIBSRC) + +$(LIBSHARED): $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) +endif + +ifdef STATIC +$(LIBOBJS): $(LIBSRC) + +$(LIBSTATIC): $(LIBOBJS) + $(LD) -r -o $@ $(LIBOBJS) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) +endif + +$(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \ + md5_crypt_good.o md5_crypt_broken.o \ + bigcrypt.o + $(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) + +unix_chkpwd.o: unix_chkpwd.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +md5_good.o: md5.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_broken.o: md5.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_crypt_good.o: md5_crypt.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \ + $(TARGET_ARCH) -c $< -o $@ + +md5_crypt_broken.o: md5_crypt.c + $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ + $(TARGET_ARCH) -c $< -o $@ + +install: all + mkdir -p $(FAKEROOT)$(SECUREDIR) +ifdef DYNAMIC + install -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) + for x in pam_unix_auth pam_unix_acct pam_unix_passwd pam_unix_session;\ + do ln -sf $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)/$$x.so ; done +endif + $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) + install -m 4555 $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED) + +remove: + rm -f $(FAKEROOT)$(SECUREDIR)/$(LIBSHARED) + for x in pam_unix_auth pam_unix_acct pam_unix_passwd pam_unix_session;\ + do rm -f $(FAKEROOT)$(SECUREDIR)/$$x.so ; done + rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) + +clean: + rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core + rm -f *~ *.a *.out *.bak + rm -rf dynamic static + +.c.o: + $(CC) -c $(CFLAGS) $< + diff --git a/Linux-PAM/modules/pam_unix/README b/Linux-PAM/modules/pam_unix/README new file mode 100644 index 00000000..d6b1f395 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/README @@ -0,0 +1,35 @@ +pam_unix comes as one module pam_unix.so. + +The following links are left for compatibility with old versions: +pam_unix_auth: authentication module providing + pam_authenticate() and pam_setcred() hooks +pam_unix_sess: session module, providing session logging +pam_unix_acct: account management, providing shadow account + managment features, password aging etc.. +pam_unix_passwd: password updating facilities providing + cracklib password strength checking facilities. + +The following options are recognized: + debug - log more debugging info + audit - a little more extreme than debug + use_first_pass - don't prompt the user for passwords + take them from PAM_ items instead + try_first_pass - don't prompt the user for the passwords + unless PAM_(OLD)AUTHTOK is unset + use_authtok - like try_first_pass, but * fail * if the new + PAM_AUTHTOK has not been previously set. + (intended for stacking password modules only) + not_set_pass - don't set the PAM_ items with the passwords + used by this module. + shadow - try to maintian a shadow based system. + md5 - when a user changes their password next, + encrypt it with the md5 algorithm. + bigcrypt - when a user changes their password next, + excrypt it with the DEC C2 - algorithm(0). + nodelay - used to prevent failed authentication + resulting in a delay of about 1 second. + nis - use NIS RPC for setting new password + remember=X - remember X old passwords, they are kept in + /etc/security/opasswd in MD5 crypted form + + invalid arguments are logged to syslog. diff --git a/Linux-PAM/modules/pam_unix/bigcrypt.c b/Linux-PAM/modules/pam_unix/bigcrypt.c new file mode 100644 index 00000000..6b73f3d2 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/bigcrypt.c @@ -0,0 +1,124 @@ +/* + * This function implements the "bigcrypt" algorithm specifically for + * Linux-PAM. + * + * This algorithm is algorithm 0 (default) shipped with the C2 secure + * implementation of Digital UNIX. + * + * Disclaimer: This work is not based on the source code to Digital + * UNIX, nor am I connected to Digital Equipment Corp, in any way + * other than as a customer. This code is based on published + * interfaces and reasonable guesswork. + * + * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8 + * characters or less. Each block is encrypted using the standard UNIX + * libc crypt function. The result of the encryption for one block + * provides the salt for the suceeding block. + * + * Restrictions: The buffer used to hold the encrypted result is + * statically allocated. (see MAX_PASS_LEN below). This is necessary, + * as the returned pointer points to "static data that are overwritten + * by each call", (XPG3: XSI System Interface + Headers pg 109), and + * this is a drop in replacement for crypt(); + * + * Andy Phillips <atp@mssl.ucl.ac.uk> + */ + +#include <string.h> +#include <stdlib.h> +#include <security/_pam_macros.h> + +char *crypt(const char *key, const char *salt); +char *bigcrypt(const char *key, const char *salt); + +/* + * Max cleartext password length in segments of 8 characters this + * function can deal with (16 segments of 8 chars= max 128 character + * password). + */ + +#define MAX_PASS_LEN 16 +#define SEGMENT_SIZE 8 +#define SALT_SIZE 2 +#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE) +#define ESEGMENT_SIZE 11 +#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1) + +char *bigcrypt(const char *key, const char *salt) +{ + char *dec_c2_cryptbuf; + + unsigned long int keylen, n_seg, j; + char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr; + char keybuf[KEYBUF_SIZE + 1]; + + D(("called with key='%s', salt='%s'.", key, salt)); + + /* reset arrays */ + dec_c2_cryptbuf = malloc(CBUF_SIZE); + if (!dec_c2_cryptbuf) { + return NULL; + } + memset(keybuf, 0, KEYBUF_SIZE + 1); + memset(dec_c2_cryptbuf, 0, CBUF_SIZE); + + /* fill KEYBUF_SIZE with key */ + strncpy(keybuf, key, KEYBUF_SIZE); + + /* deal with case that we are doing a password check for a + conventially encrypted password: the salt will be + SALT_SIZE+ESEGMENT_SIZE long. */ + if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE)) + keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */ + + keylen = strlen(keybuf); + + if (!keylen) { + n_seg = 1; + } else { + /* work out how many segments */ + n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE); + } + + if (n_seg > MAX_PASS_LEN) + n_seg = MAX_PASS_LEN; /* truncate at max length */ + + /* set up some pointers */ + cipher_ptr = dec_c2_cryptbuf; + plaintext_ptr = keybuf; + + /* do the first block with supplied salt */ + tmp_ptr = crypt(plaintext_ptr, salt); /* libc crypt() */ + + /* and place in the static area */ + strncpy(cipher_ptr, tmp_ptr, 13); + cipher_ptr += ESEGMENT_SIZE + SALT_SIZE; + plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */ + + /* change the salt (1st 2 chars of previous block) - this was found + by dowsing */ + + salt_ptr = cipher_ptr - ESEGMENT_SIZE; + + /* so far this is identical to "return crypt(key, salt);", if + there is more than one block encrypt them... */ + + if (n_seg > 1) { + for (j = 2; j <= n_seg; j++) { + + tmp_ptr = crypt(plaintext_ptr, salt_ptr); + + /* skip the salt for seg!=0 */ + strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE); + + cipher_ptr += ESEGMENT_SIZE; + plaintext_ptr += SEGMENT_SIZE; + salt_ptr = cipher_ptr - ESEGMENT_SIZE; + } + } + D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf)); + + /* this is the <NUL> terminated encrypted password */ + + return dec_c2_cryptbuf; +} diff --git a/Linux-PAM/modules/pam_unix/lckpwdf.-c b/Linux-PAM/modules/pam_unix/lckpwdf.-c new file mode 100644 index 00000000..b5ff4585 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/lckpwdf.-c @@ -0,0 +1,117 @@ +/* + * This is a hack, but until libc and glibc both include this function + * by default (libc only includes it if nys is not being used, at the + * moment, and glibc doesn't appear to have it at all) we need to have + * it here, too. :-( + * + * This should not become an official part of PAM. + * + * BEGIN_HACK + */ + +/* + * lckpwdf.c -- prevent simultaneous updates of password files + * + * Before modifying any of the password files, call lckpwdf(). It may block + * for up to 15 seconds trying to get the lock. Return value is 0 on success + * or -1 on failure. When you are done, call ulckpwdf() to release the lock. + * The lock is also released automatically when the process exits. Only one + * process at a time may hold the lock. + * + * These functions are supposed to be conformant with AT&T SVID Issue 3. + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + */ + +#include <fcntl.h> +#include <signal.h> + +#define LOCKFILE "/etc/.pwd.lock" +#define TIMEOUT 15 + +static int lockfd = -1; + +static int set_close_on_exec(int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + if (flags == -1) + return -1; + flags |= FD_CLOEXEC; + return fcntl(fd, F_SETFD, flags); +} + +static int do_lock(int fd) +{ + struct flock fl; + + memset(&fl, 0, sizeof fl); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + return fcntl(fd, F_SETLKW, &fl); +} + +static void alarm_catch(int sig) +{ +/* does nothing, but fcntl F_SETLKW will fail with EINTR */ +} + +static int lckpwdf(void) +{ + struct sigaction act, oldact; + sigset_t set, oldset; + + if (lockfd != -1) + return -1; + + lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600); + if (lockfd == -1) + return -1; + if (set_close_on_exec(lockfd) == -1) + goto cleanup_fd; + + memset(&act, 0, sizeof act); + act.sa_handler = alarm_catch; + act.sa_flags = 0; + sigfillset(&act.sa_mask); + if (sigaction(SIGALRM, &act, &oldact) == -1) + goto cleanup_fd; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1) + goto cleanup_sig; + + alarm(TIMEOUT); + if (do_lock(lockfd) == -1) + goto cleanup_alarm; + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); + sigaction(SIGALRM, &oldact, NULL); + return 0; + + cleanup_alarm: + alarm(0); + sigprocmask(SIG_SETMASK, &oldset, NULL); + cleanup_sig: + sigaction(SIGALRM, &oldact, NULL); + cleanup_fd: + close(lockfd); + lockfd = -1; + return -1; +} + +static int ulckpwdf(void) +{ + unlink(LOCKFILE); + if (lockfd == -1) + return -1; + + if (close(lockfd) == -1) { + lockfd = -1; + return -1; + } + lockfd = -1; + return 0; +} +/* END_HACK */ diff --git a/Linux-PAM/modules/pam_unix/md5.c b/Linux-PAM/modules/pam_unix/md5.c new file mode 100644 index 00000000..3fb50137 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/md5.c @@ -0,0 +1,256 @@ +/* + * $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:37 hartmans Exp $ + * + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + */ + +#include <string.h> +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +static void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Name(MD5Init)(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301U; + ctx->buf[1] = 0xefcdab89U; + ctx->buf[2] = 0x98badcfeU; + ctx->buf[3] = 0x10325476U; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/Linux-PAM/modules/pam_unix/md5.h b/Linux-PAM/modules/pam_unix/md5.h new file mode 100644 index 00000000..103f168a --- /dev/null +++ b/Linux-PAM/modules/pam_unix/md5.h @@ -0,0 +1,31 @@ + +#ifndef MD5_H +#define MD5_H + +typedef unsigned int uint32; + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +void GoodMD5Init(struct MD5Context *); +void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned); +void GoodMD5Final(unsigned char digest[16], struct MD5Context *); +void GoodMD5Transform(uint32 buf[4], uint32 const in[16]); +void BrokenMD5Init(struct MD5Context *); +void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned); +void BrokenMD5Final(unsigned char digest[16], struct MD5Context *); +void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]); + +char *Goodcrypt_md5(const char *pw, const char *salt); +char *Brokencrypt_md5(const char *pw, const char *salt); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ + +typedef struct MD5Context MD5_CTX; + +#endif /* MD5_H */ diff --git a/Linux-PAM/modules/pam_unix/md5_crypt.c b/Linux-PAM/modules/pam_unix/md5_crypt.c new file mode 100644 index 00000000..8ae84588 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/md5_crypt.c @@ -0,0 +1,154 @@ +/* + * $Id: md5_crypt.c,v 1.1.1.2 2002/09/15 20:09:01 hartmans Exp $ + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp + * + */ + +#include <string.h> +#include <stdlib.h> +#include "md5.h" + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} + +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ + +char *MD5Name(crypt_md5)(const char *pw, const char *salt) +{ + const char *magic = "$1$"; + /* This string is magic for this algorithm. Having + * it this way, we can get get better later on */ + char *passwd, *p; + const char *sp, *ep; + unsigned char final[16]; + int sl, pl, i, j; + MD5_CTX ctx, ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* TODO: now that we're using malloc'ed memory, get rid of the + strange constant buffer size. */ + passwd = malloc(120); + + /* If it starts with the magic string, then skip that */ + if (!strncmp(sp, magic, strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Name(MD5Init)(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw)); + + /* Then our magic string */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic)); + + /* Then the raw salt */ + MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + MD5Name(MD5Init)(&ctx1); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Final)(final,&ctx1); + for (pl = strlen(pw); pl > 0; pl -= 16) + MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof final); + + /* Then something really weird... */ + for (j = 0, i = strlen(pw); i; i >>= 1) + if (i & 1) + MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1); + else + MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1); + + /* Now make the output string */ + strcpy(passwd, magic); + strncat(passwd, sp, sl); + strcat(passwd, "$"); + + MD5Name(MD5Final)(final,&ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + MD5Name(MD5Init)(&ctx1); + if (i & 1) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + else + MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); + + if (i % 3) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); + + if (i % 7) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + + if (i & 1) + MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); + else + MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Name(MD5Final)(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[0] << 16) | (final[6] << 8) | final[12]; + to64(p, l, 4); + p += 4; + l = (final[1] << 16) | (final[7] << 8) | final[13]; + to64(p, l, 4); + p += 4; + l = (final[2] << 16) | (final[8] << 8) | final[14]; + to64(p, l, 4); + p += 4; + l = (final[3] << 16) | (final[9] << 8) | final[15]; + to64(p, l, 4); + p += 4; + l = (final[4] << 16) | (final[10] << 8) | final[5]; + to64(p, l, 4); + p += 4; + l = final[11]; + to64(p, l, 2); + p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof final); + + return passwd; +} diff --git a/Linux-PAM/modules/pam_unix/pam_unix_acct.c b/Linux-PAM/modules/pam_unix/pam_unix_acct.c new file mode 100644 index 00000000..178b6037 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/pam_unix_acct.c @@ -0,0 +1,204 @@ +/* + * Copyright Elliot Lee, 1996. All rights reserved. + * Copyright Jan Rêkorajski, 1999. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <security/_pam_aconf.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <syslog.h> +#include <pwd.h> +#include <shadow.h> +#include <time.h> /* for time() */ + +#include <security/_pam_macros.h> + +/* indicate that the following groups are defined */ + +#define PAM_SM_ACCOUNT + +#include <security/pam_modules.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +#include "support.h" + +/* + * PAM framework looks for this entry-point to pass control to the + * account management module. + */ + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl; + const char *uname; + int retval, daysleft; + time_t curdays; + struct spwd *spent; + struct passwd *pwent; + char buf[80]; + + D(("called.")); + + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, (const void **) &uname); + D(("user = `%s'", uname)); + if (retval != PAM_SUCCESS || uname == NULL) { + _log_err(LOG_ALERT, pamh + ,"could not identify user (from uid=%d)" + ,getuid()); + return PAM_USER_UNKNOWN; + } + + pwent = getpwnam(uname); + if (!pwent) { + _log_err(LOG_ALERT, pamh + ,"could not identify user (from getpwnam(%s))" + ,uname); + return PAM_USER_UNKNOWN; + } + + if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */ + uid_t save_euid, save_uid; + + save_euid = geteuid(); + save_uid = getuid(); + if (save_uid == pwent->pw_uid) + setreuid( save_euid, save_uid ); + else { + setreuid( 0, -1 ); + if (setreuid( -1, pwent->pw_uid ) == -1) { + setreuid( -1, 0 ); + setreuid( 0, -1 ); + if(setreuid( -1, pwent->pw_uid ) == -1) + return PAM_CRED_INSUFFICIENT; + } + } + spent = getspnam( uname ); + if (save_uid == pwent->pw_uid) + setreuid( save_uid, save_euid ); + else { + if (setreuid( -1, 0 ) == -1) + setreuid( save_uid, -1 ); + setreuid( -1, save_euid ); + } + + } else if (!strcmp( pwent->pw_passwd, "x" )) { + spent = getspnam(uname); + } else { + return PAM_SUCCESS; + } + + if (!spent) + return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ + + curdays = time(NULL) / (60 * 60 * 24); + D(("today is %d, last change %d", curdays, spent->sp_lstchg)); + if ((curdays > spent->sp_expire) && (spent->sp_expire != -1) + && (spent->sp_lstchg != 0)) { + _log_err(LOG_NOTICE, pamh + ,"account %s has expired (account expired)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "Your account has expired; please contact your system administrator"); + D(("account expired")); + return PAM_ACCT_EXPIRED; + } + if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact)) + && (spent->sp_max != -1) && (spent->sp_inact != -1) + && (spent->sp_lstchg != 0)) { + _log_err(LOG_NOTICE, pamh + ,"account %s has expired (failed to change password)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "Your account has expired; please contact your system administrator"); + D(("account expired 2")); + return PAM_ACCT_EXPIRED; + } + D(("when was the last change")); + if (spent->sp_lstchg == 0) { + _log_err(LOG_NOTICE, pamh + ,"expired password for user %s (root enforced)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "You are required to change your password immediately (root enforced)"); + D(("need a new password")); + return PAM_NEW_AUTHTOK_REQD; + } + if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) { + _log_err(LOG_DEBUG, pamh + ,"expired password for user %s (password aged)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "You are required to change your password immediately (password aged)"); + D(("need a new password 2")); + return PAM_NEW_AUTHTOK_REQD; + } + if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn)) + && (spent->sp_max != -1) && (spent->sp_warn != -1)) { + daysleft = (spent->sp_lstchg + spent->sp_max) - curdays; + _log_err(LOG_DEBUG, pamh + ,"password for user %s will expire in %d days" + ,uname, daysleft); + snprintf(buf, 80, "Warning: your password will expire in %d day%.2s", + daysleft, daysleft == 1 ? "" : "s"); + _make_remark(pamh, ctrl, PAM_TEXT_INFO, buf); + } + + D(("all done")); + + return PAM_SUCCESS; +} + + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_unix_acct_modstruct = { + "pam_unix_acct", + NULL, + NULL, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL, +}; +#endif diff --git a/Linux-PAM/modules/pam_unix/pam_unix_auth.c b/Linux-PAM/modules/pam_unix/pam_unix_auth.c new file mode 100644 index 00000000..67497e06 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/pam_unix_auth.c @@ -0,0 +1,228 @@ +/* + * Copyright Alexander O. Yuriev, 1996. All rights reserved. + * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de> + * Copyright Jan Rêkorajski, 1999. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* #define DEBUG */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +/* indicate the following groups are defined */ + +#define PAM_SM_AUTH + +#define _PAM_EXTERN_FUNCTIONS +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +#include "support.h" + +/* + * PAM framework looks for these entry-points to pass control to the + * authentication module. + */ + +/* Fun starts here :) + + * pam_sm_authenticate() performs UNIX/shadow authentication + * + * First, if shadow support is available, attempt to perform + * authentication using shadow passwords. If shadow is not + * available, or user does not have a shadow password, fallback + * onto a normal UNIX authentication + */ + +#define _UNIX_AUTHTOK "-UN*X-PASS" + +#define AUTH_RETURN \ +do { \ + if (on(UNIX_LIKE_AUTH, ctrl) && ret_data) { \ + D(("recording return code for next time [%d]", \ + retval)); \ + *ret_data = retval; \ + pam_set_data(pamh, "unix_setcred_return", \ + (void *) ret_data, setcred_free); \ + } \ + D(("done. [%s]", pam_strerror(pamh, retval))); \ + return retval; \ +} while (0) + + +static void setcred_free (pam_handle_t * pamh, void *ptr, int err) +{ + if (ptr) + free (ptr); +} + + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags + ,int argc, const char **argv) +{ + unsigned int ctrl; + int retval, *ret_data = NULL; + const char *name, *p; + + D(("called.")); + + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); + + /* Get a few bytes so we can pass our return value to + pam_sm_setcred(). */ + if (on(UNIX_LIKE_AUTH, ctrl)) + ret_data = malloc(sizeof(int)); + + /* get the user'name' */ + + retval = pam_get_user(pamh, &name, NULL); + if (retval == PAM_SUCCESS) { + /* + * Various libraries at various times have had bugs related to + * '+' or '-' as the first character of a user name. Don't take + * any chances here. Require that the username starts with an + * alphanumeric character. + */ + if (name == NULL || !isalnum(*name)) { + _log_err(LOG_ERR, pamh, "bad username [%s]", name); + retval = PAM_USER_UNKNOWN; + AUTH_RETURN; + } + if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) + D(("username [%s] obtained", name)); + } else { + D(("trouble reading username")); + if (retval == PAM_CONV_AGAIN) { + D(("pam_get_user/conv() function is not ready yet")); + /* it is safe to resume this function so we translate this + * retval to the value that indicates we're happy to resume. + */ + retval = PAM_INCOMPLETE; + } + AUTH_RETURN; + } + + /* if this user does not have a password... */ + + if (_unix_blankpasswd(ctrl, name)) { + D(("user '%s' has blank passwd", name)); + name = NULL; + retval = PAM_SUCCESS; + AUTH_RETURN; + } + /* get this user's authentication token */ + + retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL + ,_UNIX_AUTHTOK, &p); + if (retval != PAM_SUCCESS) { + if (retval != PAM_CONV_AGAIN) { + _log_err(LOG_CRIT, pamh, "auth could not identify password for [%s]" + ,name); + } else { + D(("conversation function is not ready yet")); + /* + * it is safe to resume this function so we translate this + * retval to the value that indicates we're happy to resume. + */ + retval = PAM_INCOMPLETE; + } + name = NULL; + AUTH_RETURN; + } + D(("user=%s, password=[%s]", name, p)); + + /* verify the password of this user */ + retval = _unix_verify_password(pamh, name, p, ctrl); + name = p = NULL; + + AUTH_RETURN; +} + + +/* + * The only thing _pam_set_credentials_unix() does is initialization of + * UNIX group IDs. + * + * Well, everybody but me on linux-pam is convinced that it should not + * initialize group IDs, so I am not doing it but don't say that I haven't + * warned you. -- AOY + */ + +PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags + ,int argc, const char **argv) +{ + int retval; + int *pretval = NULL; + + D(("called.")); + + retval = PAM_SUCCESS; + + D(("recovering return code from auth call")); + /* We will only find something here if UNIX_LIKE_AUTH is set -- + don't worry about an explicit check of argv. */ + pam_get_data(pamh, "unix_setcred_return", (const void **) &pretval); + if(pretval) { + retval = *pretval; + pam_set_data(pamh, "unix_setcred_return", NULL, NULL); + D(("recovered data indicates that old retval was %d", retval)); + } + + return retval; +} + +#ifdef PAM_STATIC +struct pam_module _pam_unix_auth_modstruct = { + "pam_unix_auth", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; +#endif diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c new file mode 100644 index 00000000..6b51a6b2 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c @@ -0,0 +1,1030 @@ +/* + * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + * Copyright (C) 1996. + * Copyright (c) Jan Rêkorajski, 1999. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <malloc.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <pwd.h> +#include <syslog.h> +#include <shadow.h> +#include <time.h> /* for time() */ +#include <fcntl.h> +#include <ctype.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> + +#ifdef USE_CRACKLIB +#include <crack.h> +#endif + +#include <security/_pam_macros.h> + +/* indicate the following groups are defined */ + +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +#include "yppasswd.h" +#include "md5.h" +#include "support.h" + +#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) +extern int getrpcport(const char *host, unsigned long prognum, + unsigned long versnum, unsigned int proto); +#endif /* GNU libc 2.1 */ + +/* + * PAM framework looks for these entry-points to pass control to the + * password changing module. + */ + +#ifdef NEED_LCKPWDF +#include "./lckpwdf.-c" +#endif + +extern char *bigcrypt(const char *key, const char *salt); + +/* + How it works: + Gets in username (has to be done) from the calling program + Does authentication of user (only if we are not running as root) + Gets new password/checks for sanity + Sets it. + */ + +/* passwd/salt conversion macros */ + +#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') +#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') + +/* data tokens */ + +#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS" +#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS" + +#define MAX_PASSWD_TRIES 3 +#define PW_TMPFILE "/etc/npasswd" +#define SH_TMPFILE "/etc/nshadow" +#define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict" +#define OPW_TMPFILE "/etc/security/nopasswd" +#define OLD_PASSWORDS_FILE "/etc/security/opasswd" + +/* + * i64c - convert an integer to a radix 64 character + */ +static int i64c(int i) +{ + if (i < 0) + return ('.'); + else if (i > 63) + return ('z'); + if (i == 0) + return ('.'); + if (i == 1) + return ('/'); + if (i >= 2 && i <= 11) + return ('0' - 2 + i); + if (i >= 12 && i <= 37) + return ('A' - 12 + i); + if (i >= 38 && i <= 63) + return ('a' - 38 + i); + return ('\0'); +} + +static char *crypt_md5_wrapper(const char *pass_new) +{ + /* + * Code lifted from Marek Michalkiewicz's shadow suite. (CG) + * removed use of static variables (AGM) + */ + + struct timeval tv; + MD5_CTX ctx; + unsigned char result[16]; + char *cp = (char *) result; + unsigned char tmp[16]; + int i; + char *x = NULL; + + GoodMD5Init(&ctx); + gettimeofday(&tv, (struct timezone *) 0); + GoodMD5Update(&ctx, (void *) &tv, sizeof tv); + i = getpid(); + GoodMD5Update(&ctx, (void *) &i, sizeof i); + i = clock(); + GoodMD5Update(&ctx, (void *) &i, sizeof i); + GoodMD5Update(&ctx, result, sizeof result); + GoodMD5Final(tmp, &ctx); + strcpy(cp, "$1$"); /* magic for the MD5 */ + cp += strlen(cp); + for (i = 0; i < 8; i++) + *cp++ = i64c(tmp[i] & 077); + *cp = '\0'; + + /* no longer need cleartext */ + x = Goodcrypt_md5(pass_new, (const char *) result); + + return x; +} + +static char *getNISserver(pam_handle_t *pamh) +{ + char *master; + char *domainname; + int port, err; + + if ((err = yp_get_default_domain(&domainname)) != 0) { + _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n", + yperr_string(err)); + return NULL; + } + if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) { + _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n", + yperr_string(err)); + return NULL; + } + port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); + if (port == 0) { + _log_err(LOG_WARNING, pamh, + "yppasswdd not running on NIS master host\n"); + return NULL; + } + if (port >= IPPORT_RESERVED) { + _log_err(LOG_WARNING, pamh, + "yppasswd daemon running on illegal port.\n"); + return NULL; + } + return master; +} + +static int check_old_password(const char *forwho, const char *newpass) +{ + static char buf[16384]; + char *s_luser, *s_uid, *s_npas, *s_pas; + int retval = PAM_SUCCESS; + FILE *opwfile; + + opwfile = fopen(OLD_PASSWORDS_FILE, "r"); + if (opwfile == NULL) + return PAM_AUTHTOK_ERR; + + while (fgets(buf, 16380, opwfile)) { + if (!strncmp(buf, forwho, strlen(forwho))) { + buf[strlen(buf) - 1] = '\0'; + s_luser = strtok(buf, ":,"); + s_uid = strtok(NULL, ":,"); + s_npas = strtok(NULL, ":,"); + s_pas = strtok(NULL, ":,"); + while (s_pas != NULL) { + char *md5pass = Goodcrypt_md5(newpass, s_pas); + if (!strcmp(md5pass, s_pas)) { + _pam_delete(md5pass); + retval = PAM_AUTHTOK_ERR; + break; + } + s_pas = strtok(NULL, ":,"); + _pam_delete(md5pass); + } + break; + } + } + fclose(opwfile); + + return retval; +} + +static int save_old_password(const char *forwho, const char *oldpass, + int howmany) +{ + static char buf[16384]; + static char nbuf[16384]; + char *s_luser, *s_uid, *s_npas, *s_pas, *pass; + int npas; + FILE *pwfile, *opwfile; + int err = 0; + int oldmask; + int found = 0; + struct passwd *pwd = NULL; + + if (howmany < 0) { + return PAM_SUCCESS; + } + + if (oldpass == NULL) { + return PAM_SUCCESS; + } + + oldmask = umask(077); + pwfile = fopen(OPW_TMPFILE, "w"); + umask(oldmask); + if (pwfile == NULL) { + return PAM_AUTHTOK_ERR; + } + + opwfile = fopen(OLD_PASSWORDS_FILE, "r"); + if (opwfile == NULL) { + fclose(pwfile); + return PAM_AUTHTOK_ERR; + } + + chown(OPW_TMPFILE, 0, 0); + chmod(OPW_TMPFILE, 0600); + + while (fgets(buf, 16380, opwfile)) { + if (!strncmp(buf, forwho, strlen(forwho))) { + buf[strlen(buf) - 1] = '\0'; + s_luser = strtok(buf, ":"); + s_uid = strtok(NULL, ":"); + s_npas = strtok(NULL, ":"); + s_pas = strtok(NULL, ":"); + npas = strtol(s_npas, NULL, 10) + 1; + while (npas > howmany) { + s_pas = strpbrk(s_pas, ","); + if (s_pas != NULL) + s_pas++; + npas--; + } + pass = crypt_md5_wrapper(oldpass); + if (s_pas == NULL) + snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n", + s_luser, s_uid, npas, pass); + else + snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n", + s_luser, s_uid, npas, s_pas, pass); + _pam_delete(pass); + if (fputs(nbuf, pwfile) < 0) { + err = 1; + break; + } + found = 1; + } else if (fputs(buf, pwfile) < 0) { + err = 1; + break; + } + } + fclose(opwfile); + + if (!found) { + pwd = getpwnam(forwho); + if (pwd == NULL) { + err = 1; + } else { + pass = crypt_md5_wrapper(oldpass); + snprintf(nbuf, sizeof(nbuf), "%s:%d:1:%s\n", + forwho, pwd->pw_uid, pass); + _pam_delete(pass); + if (fputs(nbuf, pwfile) < 0) { + err = 1; + } + } + } + + if (fclose(pwfile)) { + D(("error writing entries to old passwords file: %s\n", + strerror(errno))); + err = 1; + } + + if (!err) { + rename(OPW_TMPFILE, OLD_PASSWORDS_FILE); + return PAM_SUCCESS; + } else { + unlink(OPW_TMPFILE); + return PAM_AUTHTOK_ERR; + } +} + +static int _update_passwd(pam_handle_t *pamh, + const char *forwho, const char *towhat) +{ + struct passwd *tmpent = NULL; + FILE *pwfile, *opwfile; + int err = 1; + int oldmask; + + oldmask = umask(077); + pwfile = fopen(PW_TMPFILE, "w"); + umask(oldmask); + if (pwfile == NULL) { + return PAM_AUTHTOK_ERR; + } + + opwfile = fopen("/etc/passwd", "r"); + if (opwfile == NULL) { + fclose(pwfile); + return PAM_AUTHTOK_ERR; + } + + chown(PW_TMPFILE, 0, 0); + chmod(PW_TMPFILE, 0644); + tmpent = fgetpwent(opwfile); + while (tmpent) { + if (!strcmp(tmpent->pw_name, forwho)) { + /* To shut gcc up */ + union { + const char *const_charp; + char *charp; + } assigned_passwd; + assigned_passwd.const_charp = towhat; + + tmpent->pw_passwd = assigned_passwd.charp; + err = 0; + } + if (putpwent(tmpent, pwfile)) { + D(("error writing entry to password file: %s\n", strerror(errno))); + err = 1; + break; + } + tmpent = fgetpwent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + D(("error writing entries to password file: %s\n", strerror(errno))); + err = 1; + } + + if (!err) { + rename(PW_TMPFILE, "/etc/passwd"); + _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); + return PAM_SUCCESS; + } else { + unlink(PW_TMPFILE); + return PAM_AUTHTOK_ERR; + } +} + +static int _update_shadow(const char *forwho, char *towhat) +{ + struct spwd *spwdent = NULL, *stmpent = NULL; + FILE *pwfile, *opwfile; + int err = 1; + int oldmask; + + spwdent = getspnam(forwho); + if (spwdent == NULL) { + return PAM_USER_UNKNOWN; + } + oldmask = umask(077); + pwfile = fopen(SH_TMPFILE, "w"); + umask(oldmask); + if (pwfile == NULL) { + return PAM_AUTHTOK_ERR; + } + + opwfile = fopen("/etc/shadow", "r"); + if (opwfile == NULL) { + fclose(pwfile); + return PAM_AUTHTOK_ERR; + } + + chown(SH_TMPFILE, 0, 0); + chmod(SH_TMPFILE, 0600); + stmpent = fgetspent(opwfile); + while (stmpent) { + + if (!strcmp(stmpent->sp_namp, forwho)) { + stmpent->sp_pwdp = towhat; + stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); + err = 0; + D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); + } + + if (putspent(stmpent, pwfile)) { + D(("error writing entry to shadow file: %s\n", strerror(errno))); + err = 1; + break; + } + + stmpent = fgetspent(opwfile); + } + fclose(opwfile); + + if (fclose(pwfile)) { + D(("error writing entries to shadow file: %s\n", strerror(errno))); + err = 1; + } + + if (!err) { + rename(SH_TMPFILE, "/etc/shadow"); + return PAM_SUCCESS; + } else { + unlink(SH_TMPFILE); + return PAM_AUTHTOK_ERR; + } +} + +static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, + char *towhat, unsigned int ctrl, int remember) +{ + struct passwd *pwd = NULL; + int retval = 0; + + D(("called")); + + setpwent(); + pwd = getpwnam(forwho); + endpwent(); + + if (pwd == NULL) + return PAM_AUTHTOK_ERR; + + if (on(UNIX_NIS, ctrl)) { + struct timeval timeout; + struct yppasswd yppwd; + CLIENT *clnt; + char *master; + int status; + int err = 0; + + /* Make RPC call to NIS server */ + if ((master = getNISserver(pamh)) == NULL) + return PAM_TRY_AGAIN; + + /* Initialize password information */ + yppwd.newpw.pw_passwd = pwd->pw_passwd; + yppwd.newpw.pw_name = pwd->pw_name; + yppwd.newpw.pw_uid = pwd->pw_uid; + yppwd.newpw.pw_gid = pwd->pw_gid; + yppwd.newpw.pw_gecos = pwd->pw_gecos; + yppwd.newpw.pw_dir = pwd->pw_dir; + yppwd.newpw.pw_shell = pwd->pw_shell; + yppwd.oldpass = fromwhat; + yppwd.newpw.pw_passwd = towhat; + + D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); + + /* The yppasswd.x file said `unix authentication required', + * so I added it. This is the only reason it is in here. + * My yppasswdd doesn't use it, but maybe some others out there + * do. --okir + */ + clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); + clnt->cl_auth = authunix_create_default(); + memset((char *) &status, '\0', sizeof(status)); + timeout.tv_sec = 25; + timeout.tv_usec = 0; + err = clnt_call(clnt, YPPASSWDPROC_UPDATE, + (xdrproc_t) xdr_yppasswd, (char *) &yppwd, + (xdrproc_t) xdr_int, (char *) &status, + timeout); + + if (err) { + clnt_perrno(err); + retval = PAM_TRY_AGAIN; + } else if (status) { + D(("Error while changing NIS password.\n")); + retval = PAM_TRY_AGAIN; + } + D(("The password has%s been changed on %s.", + (err || status) ? " not" : "", master)); + _log_err(LOG_NOTICE, pamh, "password%s changed for %s on %s", + (err || status) ? " not" : "", pwd->pw_name, master); + + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + if ((err || status) != 0) { + retval = PAM_TRY_AGAIN; + } +#ifdef DEBUG + sleep(5); +#endif + return retval; + } + /* first, save old password */ + if (save_old_password(forwho, fromwhat, remember)) { + return PAM_AUTHTOK_ERR; + } + if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { + retval = _update_shadow(forwho, towhat); + if (retval == PAM_SUCCESS) + retval = _update_passwd(pamh, forwho, "x"); + } else { + retval = _update_passwd(pamh, forwho, towhat); + } + + return retval; +} + +static int _unix_verify_shadow(const char *user, unsigned int ctrl) +{ + struct passwd *pwd = NULL; /* Password and shadow password */ + struct spwd *spwdent = NULL; /* file entries for the user */ + time_t curdays; + int retval = PAM_SUCCESS; + + /* UNIX passwords area */ + setpwent(); + pwd = getpwnam(user); /* Get password file entry... */ + endpwent(); + if (pwd == NULL) + return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ + + if (strcmp(pwd->pw_passwd, "x") == 0) { + /* ...and shadow password file entry for this user, if shadowing + is enabled */ + setspent(); + spwdent = getspnam(user); + endspent(); + + if (spwdent == NULL) + return PAM_AUTHINFO_UNAVAIL; + } else { + if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ + uid_t save_uid; + + save_uid = geteuid(); + seteuid (pwd->pw_uid); + spwdent = getspnam( user ); + seteuid (save_uid); + + if (spwdent == NULL) + return PAM_AUTHINFO_UNAVAIL; + } else + spwdent = NULL; + } + + if (spwdent != NULL) { + /* We have the user's information, now let's check if their account + has expired (60 * 60 * 24 = number of seconds in a day) */ + + if (off(UNIX__IAMROOT, ctrl)) { + /* Get the current number of days since 1970 */ + curdays = time(NULL) / (60 * 60 * 24); + if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) + && (spwdent->sp_min != -1)) + retval = PAM_AUTHTOK_ERR; + else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) + && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1) + && (spwdent->sp_lstchg != 0)) + /* + * Their password change has been put off too long, + */ + retval = PAM_ACCT_EXPIRED; + else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1) + && (spwdent->sp_lstchg != 0)) + /* + * OR their account has just plain expired + */ + retval = PAM_ACCT_EXPIRED; + } + } + return retval; +} + +static int _pam_unix_approve_pass(pam_handle_t * pamh + ,unsigned int ctrl + ,const char *pass_old + ,const char *pass_new) +{ + const char *user; + const char *remark = NULL; + int retval = PAM_SUCCESS; + + D(("&new=%p, &old=%p", pass_old, pass_new)); + D(("new=[%s]", pass_new)); + D(("old=[%s]", pass_old)); + + if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) { + if (on(UNIX_DEBUG, ctrl)) { + _log_err(LOG_DEBUG, pamh, "bad authentication token"); + } + _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? + "No password supplied" : "Password unchanged"); + return PAM_AUTHTOK_ERR; + } + /* + * if one wanted to hardwire authentication token strength + * checking this would be the place - AGM + */ + + retval = pam_get_item(pamh, PAM_USER, (const void **) &user); + if (retval != PAM_SUCCESS) { + if (on(UNIX_DEBUG, ctrl)) { + _log_err(LOG_ERR, pamh, "Can not get username"); + return PAM_AUTHTOK_ERR; + } + } + if (off(UNIX__IAMROOT, ctrl)) { +#ifdef USE_CRACKLIB + remark = FascistCheck(pass_new, CRACKLIB_DICTS); + D(("called cracklib [%s]", remark)); +#else + if (strlen(pass_new) < 6) + remark = "You must choose a longer password"; + D(("lenth check [%s]", remark)); +#endif + if (on(UNIX_REMEMBER_PASSWD, ctrl)) + if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS) + remark = "Password has been already used. Choose another."; + } + if (remark) { + _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); + retval = PAM_AUTHTOK_ERR; + } + return retval; +} + + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, + int argc, const char **argv) +{ + unsigned int ctrl, lctrl; + int retval, i; + int remember = -1; + + /* <DO NOT free() THESE> */ + const char *user; + char *pass_old, *pass_new; + /* </DO NOT free() THESE> */ + + D(("called.")); + +#ifdef USE_LCKPWDF + /* our current locking system requires that we lock the + entire password database. This avoids both livelock + and deadlock. */ + /* These values for the number of attempts and the sleep time + are, of course, completely arbitrary. + My reading of the PAM docs is that, once pam_chauthtok() has been + called with PAM_UPDATE_AUTHTOK, we are obliged to take any + reasonable steps to make sure the token is updated; so retrying + for 1/10 sec. isn't overdoing it. + The other possibility is to call lckpwdf() on the first + pam_chauthtok() pass, and hold the lock until released in the + second pass--but is this guaranteed to work? -SRL */ + i=0; + while((retval = lckpwdf()) != 0 && i < 100) { + usleep(1000); + } + if(retval != 0) { + return PAM_AUTHTOK_LOCK_BUSY; + } +#endif + ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); + + /* + * First get the name of a user + */ + retval = pam_get_user(pamh, &user, "Username: "); + if (retval == PAM_SUCCESS) { + /* + * Various libraries at various times have had bugs related to + * '+' or '-' as the first character of a user name. Don't take + * any chances here. Require that the username starts with an + * alphanumeric character. + */ + if (user == NULL || !isalnum(*user)) { + _log_err(LOG_ERR, pamh, "bad username [%s]", user); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return PAM_USER_UNKNOWN; + } + if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) + _log_err(LOG_DEBUG, pamh, "username [%s] obtained", + user); + } else { + if (on(UNIX_DEBUG, ctrl)) + _log_err(LOG_DEBUG, pamh, + "password - could not identify user"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + + D(("Got username of %s", user)); + + /* + * This is not an AUTH module! + */ + if (on(UNIX__NONULL, ctrl)) + set(UNIX__NULLOK, ctrl); + + if (on(UNIX__PRELIM, ctrl)) { + /* + * obtain and verify the current password (OLDAUTHTOK) for + * the user. + */ + char *Announce; + + D(("prelim check")); + + if (_unix_blankpasswd(ctrl, user)) { +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return PAM_SUCCESS; + } else if (off(UNIX__IAMROOT, ctrl)) { + + /* instruct user what is happening */ +#define greeting "Changing password for " + Announce = (char *) malloc(sizeof(greeting) + strlen(user)); + if (Announce == NULL) { + _log_err(LOG_CRIT, pamh, + "password - out of memory"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return PAM_BUF_ERR; + } + (void) strcpy(Announce, greeting); + (void) strcpy(Announce + sizeof(greeting) - 1, user); +#undef greeting + + lctrl = ctrl; + set(UNIX__OLD_PASSWD, lctrl); + retval = _unix_read_password(pamh, lctrl + ,Announce + ,"(current) UNIX password: " + ,NULL + ,_UNIX_OLD_AUTHTOK + ,(const char **) &pass_old); + free(Announce); + + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh + ,"password - (old) token not obtained"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + /* verify that this is the password for this user */ + + retval = _unix_verify_password(pamh, user, pass_old, ctrl); + } else { + D(("process run by root so do nothing this time around")); + pass_old = NULL; + retval = PAM_SUCCESS; /* root doesn't have too */ + } + + if (retval != PAM_SUCCESS) { + D(("Authentication failed")); + pass_old = NULL; +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); + pass_old = NULL; + if (retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh, + "failed to set PAM_OLDAUTHTOK"); + } + retval = _unix_verify_shadow(user, ctrl); + if (retval == PAM_AUTHTOK_ERR) { + if (off(UNIX__IAMROOT, ctrl)) + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "You must wait longer to change your password"); + else + retval = PAM_SUCCESS; + } + } else if (on(UNIX__UPDATE, ctrl)) { + /* + * tpass is used below to store the _pam_md() return; it + * should be _pam_delete()'d. + */ + + char *tpass = NULL; + int retry = 0; + + /* + * obtain the proposed password + */ + + D(("do update")); + + /* + * get the old token back. NULL was ok only if root [at this + * point we assume that this has already been enforced on a + * previous call to this function]. + */ + + if (off(UNIX_NOT_SET_PASS, ctrl)) { + retval = pam_get_item(pamh, PAM_OLDAUTHTOK + ,(const void **) &pass_old); + } else { + retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK + ,(const void **) &pass_old); + if (retval == PAM_NO_MODULE_DATA) { + retval = PAM_SUCCESS; + pass_old = NULL; + } + } + D(("pass_old [%s]", pass_old)); + + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user not authenticated"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + retval = _unix_verify_shadow(user, ctrl); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + D(("get new password now")); + + lctrl = ctrl; + + if (on(UNIX_USE_AUTHTOK, lctrl)) { + set(UNIX_USE_FIRST_PASS, lctrl); + } + retry = 0; + retval = PAM_AUTHTOK_ERR; + while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { + /* + * use_authtok is to force the use of a previously entered + * password -- needed for pluggable password strength checking + */ + + retval = _unix_read_password(pamh, lctrl + ,NULL + ,"Enter new UNIX password: " + ,"Retype new UNIX password: " + ,_UNIX_NEW_AUTHTOK + ,(const char **) &pass_new); + + if (retval != PAM_SUCCESS) { + if (on(UNIX_DEBUG, ctrl)) { + _log_err(LOG_ALERT, pamh + ,"password - new password not obtained"); + } + pass_old = NULL; /* tidy up */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + D(("returned to _unix_chauthtok")); + + /* + * At this point we know who the user is and what they + * propose as their new password. Verify that the new + * password is acceptable. + */ + + if (pass_new[0] == '\0') { /* "\0" password = NULL */ + pass_new = NULL; + } + retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); + } + + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, + "new password not acceptable"); + pass_new = pass_old = NULL; /* tidy up */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + /* + * By reaching here we have approved the passwords and must now + * rebuild the password database file. + */ + + /* + * First we encrypt the new password. + */ + + if (on(UNIX_MD5_PASS, ctrl)) { + tpass = crypt_md5_wrapper(pass_new); + } else { + /* + * Salt manipulation is stolen from Rick Faith's passwd + * program. Sorry Rick :) -- alex + */ + + time_t tm; + char salt[3]; + + time(&tm); + salt[0] = bin_to_ascii(tm & 0x3f); + salt[1] = bin_to_ascii((tm >> 6) & 0x3f); + salt[2] = '\0'; + + if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { + /* + * to avoid using the _extensions_ of the bigcrypt() + * function we truncate the newly entered password + * [Problems that followed from this are fixed as per + * Bug 521314.] + */ + char *temp = malloc(9); + + if (temp == NULL) { + _log_err(LOG_CRIT, pamh, + "out of memory for password"); + pass_new = pass_old = NULL; /* tidy up */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return PAM_BUF_ERR; + } + /* copy first 8 bytes of password */ + strncpy(temp, pass_new, 8); + temp[8] = '\0'; + + /* no longer need cleartext */ + tpass = bigcrypt(temp, salt); + + _pam_delete(temp); /* tidy up */ + } else { + tpass = bigcrypt(pass_new, salt); + } + } + + D(("password processed")); + + /* update the password database(s) -- race conditions..? */ + + retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, + remember); + _pam_delete(tpass); + pass_old = pass_new = NULL; + } else { /* something has broken with the module */ + _log_err(LOG_ALERT, pamh, + "password received unknown request"); + retval = PAM_ABORT; + } + + D(("retval was %d", retval)); + +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; +} + + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_unix_passwd_modstruct = { + "pam_unix_passwd", + NULL, + NULL, + NULL, + NULL, + NULL, + pam_sm_chauthtok, +}; +#endif + diff --git a/Linux-PAM/modules/pam_unix/pam_unix_sess.c b/Linux-PAM/modules/pam_unix/pam_unix_sess.c new file mode 100644 index 00000000..0784bff8 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/pam_unix_sess.c @@ -0,0 +1,141 @@ +/* + * $Id: pam_unix_sess.c,v 1.1.1.1 2001/04/29 04:17:39 hartmans Exp $ + * + * Copyright Alexander O. Yuriev, 1996. All rights reserved. + * Copyright Jan Rêkorajski, 1999. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <security/_pam_aconf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +/* indicate the following groups are defined */ + +#define PAM_SM_SESSION + +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ + +#include "support.h" + +/* + * PAM framework looks for these entry-points to pass control to the + * session module. + */ + +PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, + int argc, const char **argv) +{ + char *user_name, *service; + unsigned int ctrl; + int retval; + + D(("called.")); + + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); + if (user_name == NULL || retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh, + "open_session - error recovering username"); + return PAM_SESSION_ERR; /* How did we get authenticated with + no username?! */ + } + retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); + if (service == NULL || retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh, + "open_session - error recovering service"); + return PAM_SESSION_ERR; + } + _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)" + ,user_name + ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid()); + + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, + int argc, const char **argv) +{ + char *user_name, *service; + unsigned int ctrl; + int retval; + + D(("called.")); + + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); + if (user_name == NULL || retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh, + "close_session - error recovering username"); + return PAM_SESSION_ERR; /* How did we get authenticated with + no username?! */ + } + retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); + if (service == NULL || retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh, + "close_session - error recovering service"); + return PAM_SESSION_ERR; + } + _log_err(LOG_INFO, pamh, "session closed for user %s" + ,user_name); + + return PAM_SUCCESS; +} + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_unix_session_modstruct = { + "pam_unix_session", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; +#endif + diff --git a/Linux-PAM/modules/pam_unix/support.c b/Linux-PAM/modules/pam_unix/support.c new file mode 100644 index 00000000..15861af6 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/support.c @@ -0,0 +1,923 @@ +/* + * $Id: support.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * + * Copyright information at end of file. + */ + +#define _BSD_SOURCE + +#include <stdlib.h> +#include <unistd.h> +#include <stdarg.h> +#include <string.h> +#include <malloc.h> +#include <pwd.h> +#include <shadow.h> +#include <limits.h> +#include <utmp.h> +#include <errno.h> + +#include <security/_pam_macros.h> +#include <security/pam_modules.h> + +#include "md5.h" +#include "support.h" + +extern char *crypt(const char *key, const char *salt); +extern char *bigcrypt(const char *key, const char *salt); + +/* syslogging function for errors and other information */ + +void _log_err(int err, pam_handle_t *pamh, const char *format,...) +{ + char *service = NULL; + char logname[256]; + va_list args; + + pam_get_item(pamh, PAM_SERVICE, (const void **) &service); + if (service) { + strncpy(logname, service, sizeof(logname)); + logname[sizeof(logname) - 1 - strlen("(pam_unix)")] = '\0'; + strncat(logname, "(pam_unix)", strlen("(pam_unix)")); + } else { + strncpy(logname, "pam_unix", sizeof(logname) - 1); + } + + va_start(args, format); + openlog(logname, LOG_CONS | LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* this is a front-end for module-application conversations */ + +static int converse(pam_handle_t * pamh, int ctrl, int nargs + ,struct pam_message **message + ,struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + D(("begin to converse")); + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (retval == PAM_SUCCESS) { + + retval = conv->conv(nargs, (const struct pam_message **) message + ,response, conv->appdata_ptr); + + D(("returned from application's conversation function")); + + if (retval != PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) { + _log_err(LOG_DEBUG, pamh, "conversation failure [%s]" + ,pam_strerror(pamh, retval)); + } + } else if (retval != PAM_CONV_AGAIN) { + _log_err(LOG_ERR, pamh + ,"couldn't obtain coversation function [%s]" + ,pam_strerror(pamh, retval)); + } + D(("ready to return from module conversation")); + + return retval; /* propagate error status */ +} + +int _make_remark(pam_handle_t * pamh, unsigned int ctrl + ,int type, const char *text) +{ + int retval = PAM_SUCCESS; + + if (off(UNIX__QUIET, ctrl)) { + struct pam_message *pmsg[1], msg[1]; + struct pam_response *resp; + + pmsg[0] = &msg[0]; + msg[0].msg = text; + msg[0].msg_style = type; + + resp = NULL; + retval = converse(pamh, ctrl, 1, pmsg, &resp); + + if (resp) { + _pam_drop_reply(resp, 1); + } + } + return retval; +} + + /* + * Beacause getlogin() is braindead and sometimes it just + * doesn't work, we reimplement it here. + */ +char *PAM_getlogin(void) +{ + struct utmp *ut, line; + char *curr_tty, *retval; + static char curr_user[sizeof(ut->ut_user) + 4]; + + retval = NULL; + + curr_tty = ttyname(0); + if (curr_tty != NULL) { + D(("PAM_getlogin ttyname: %s", curr_tty)); + curr_tty += 5; + setutent(); + strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); + if ((ut = getutline(&line)) != NULL) { + strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); + curr_user[sizeof(curr_user) - 1] = '\0'; + retval = curr_user; + } + endutent(); + } + D(("PAM_getlogin retval: %s", retval)); + + return retval; +} + +/* + * set the control flags for the UNIX module. + */ + +int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, + const char **argv) +{ + unsigned int ctrl; + + D(("called.")); + + ctrl = UNIX_DEFAULTS; /* the default selection of options */ + + /* set some flags manually */ + + if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) { + D(("IAMROOT")); + set(UNIX__IAMROOT, ctrl); + } + if (flags & PAM_UPDATE_AUTHTOK) { + D(("UPDATE_AUTHTOK")); + set(UNIX__UPDATE, ctrl); + } + if (flags & PAM_PRELIM_CHECK) { + D(("PRELIM_CHECK")); + set(UNIX__PRELIM, ctrl); + } + if (flags & PAM_DISALLOW_NULL_AUTHTOK) { + D(("DISALLOW_NULL_AUTHTOK")); + set(UNIX__NONULL, ctrl); + } + if (flags & PAM_SILENT) { + D(("SILENT")); + set(UNIX__QUIET, ctrl); + } + /* now parse the arguments to this module */ + + while (argc-- > 0) { + int j; + + D(("pam_unix arg: %s", *argv)); + + for (j = 0; j < UNIX_CTRLS_; ++j) { + if (unix_args[j].token + && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token))) { + break; + } + } + + if (j >= UNIX_CTRLS_) { + _log_err(LOG_ERR, pamh, + "unrecognized option [%s]", *argv); + } else { + ctrl &= unix_args[j].mask; /* for turning things off */ + ctrl |= unix_args[j].flag; /* for turning things on */ + + if (remember != NULL) { + if (j == UNIX_REMEMBER_PASSWD) { + *remember = strtol(*argv + 9, NULL, 10); + if ((*remember == LONG_MIN) || (*remember == LONG_MAX)) + *remember = -1; + if (*remember > 400) + *remember = 400; + } + } + } + + ++argv; /* step to next argument */ + } + + /* auditing is a more sensitive version of debug */ + + if (on(UNIX_AUDIT, ctrl)) { + set(UNIX_DEBUG, ctrl); + } + /* return the set of flags */ + + D(("done.")); + return ctrl; +} + +static void _cleanup(pam_handle_t * pamh, void *x, int error_status) +{ + _pam_delete(x); +} + +/* ************************************************************** * + * Useful non-trivial functions * + * ************************************************************** */ + + /* + * the following is used to keep track of the number of times a user fails + * to authenticate themself. + */ + +#define FAIL_PREFIX "-UN*X-FAIL-" +#define UNIX_MAX_RETRIES 3 + +struct _pam_failed_auth { + char *user; /* user that's failed to be authenticated */ + char *name; /* attempt from user with name */ + int uid; /* uid of calling user */ + int euid; /* euid of calling process */ + int count; /* number of failures so far */ +}; + +#ifndef PAM_DATA_REPLACE +#error "Need to get an updated libpam 0.52 or better" +#endif + +static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err) +{ + int quiet; + const char *service = NULL; + const char *ruser = NULL; + const char *rhost = NULL; + const char *tty = NULL; + struct _pam_failed_auth *failure; + + D(("called")); + + quiet = err & PAM_DATA_SILENT; /* should we log something? */ + err &= PAM_DATA_REPLACE; /* are we just replacing data? */ + failure = (struct _pam_failed_auth *) fl; + + if (failure != NULL) { + + if (!quiet && !err) { /* under advisement from Sun,may go away */ + + /* log the number of authentication failures */ + if (failure->count > 1) { + (void) pam_get_item(pamh, PAM_SERVICE, + (const void **)&service); + (void) pam_get_item(pamh, PAM_RUSER, + (const void **)&ruser); + (void) pam_get_item(pamh, PAM_RHOST, + (const void **)&rhost); + (void) pam_get_item(pamh, PAM_TTY, + (const void **)&tty); + _log_err(LOG_NOTICE, pamh, + "%d more authentication failure%s; " + "logname=%s uid=%d euid=%d " + "tty=%s ruser=%s rhost=%s " + "%s%s", + failure->count - 1, failure->count == 2 ? "" : "s", + failure->name, failure->uid, failure->euid, + tty ? tty : "", ruser ? ruser : "", + rhost ? rhost : "", + (failure->user && failure->user[0] != '\0') + ? " user=" : "", failure->user + ); + + if (failure->count > UNIX_MAX_RETRIES) { + _log_err(LOG_ALERT, pamh + ,"service(%s) ignoring max retries; %d > %d" + ,service == NULL ? "**unknown**" : service + ,failure->count + ,UNIX_MAX_RETRIES); + } + } + } + _pam_delete(failure->user); /* tidy up */ + _pam_delete(failure->name); /* tidy up */ + free(failure); + } +} + +/* + * _unix_blankpasswd() is a quick check for a blank password + * + * returns TRUE if user does not have a password + * - to avoid prompting for one in such cases (CG) + */ + +int _unix_blankpasswd(unsigned int ctrl, const char *name) +{ + struct passwd *pwd = NULL; + struct spwd *spwdent = NULL; + char *salt = NULL; + int retval; +#if HAVE_GETPWNAM_R + char *buf = NULL; + int bufsize = 0; + struct passwd pwd_buf; + + pwd = &pwd_buf; +#endif + + D(("called")); + + /* + * This function does not have to be too smart if something goes + * wrong, return FALSE and let this case to be treated somewhere + * else (CG) + */ + + if (on(UNIX__NONULL, ctrl)) + return 0; /* will fail but don't let on yet */ + + /* UNIX passwords area */ + + /* Get password file entry... */ +#if HAVE_GETPWNAM_R + bufsize = 1024; + buf = malloc(bufsize); + + if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { + pwd = NULL; + } + while (retval == ERANGE) { + bufsize += 1024; + buf = realloc(buf, bufsize); + if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { + pwd = NULL; + } + } +#else + pwd = getpwnam(name); +#endif + + if (pwd != NULL) { + if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) + { /* NIS+ */ + uid_t save_euid, save_uid; + + save_euid = geteuid(); + save_uid = getuid(); + if (save_uid == pwd->pw_uid) + setreuid( save_euid, save_uid ); + else { + setreuid( 0, -1 ); + if (setreuid( -1, pwd->pw_uid ) == -1) { + setreuid( -1, 0 ); + setreuid( 0, -1 ); + if(setreuid( -1, pwd->pw_uid ) == -1) + /* Will fail elsewhere. */ +#if HAVE_GETPWNAM_R + if (buf) + free(buf); +#endif + return 0; + } + } + + spwdent = getspnam( name ); + if (save_uid == pwd->pw_uid) + setreuid( save_uid, save_euid ); + else { + if (setreuid( -1, 0 ) == -1) + setreuid( save_uid, -1 ); + setreuid( -1, save_euid ); + } + } else if (strcmp(pwd->pw_passwd, "x") == 0) { + /* + * ...and shadow password file entry for this user, + * if shadowing is enabled + */ + spwdent = getspnam(name); + } + if (spwdent) + salt = x_strdup(spwdent->sp_pwdp); + else + salt = x_strdup(pwd->pw_passwd); + } + /* Does this user have a password? */ + if (salt == NULL) { + retval = 0; + } else { + if (strlen(salt) == 0) + retval = 1; + else + retval = 0; + } + + /* tidy up */ + + if (salt) + _pam_delete(salt); + +#if HAVE_GETPWNAM_R + if (buf) + free(buf); +#endif + + return retval; +} + +/* + * verify the password of a user + */ + +#include <sys/types.h> +#include <sys/wait.h> + +static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, + unsigned int ctrl, const char *user) +{ + int retval, child, fds[2]; + + D(("called.")); + /* create a pipe for the password */ + if (pipe(fds) != 0) { + D(("could not make pipe")); + return PAM_AUTH_ERR; + } + + /* fork */ + child = fork(); + if (child == 0) { + static char *envp[] = { NULL }; + char *args[] = { NULL, NULL, NULL }; + + /* XXX - should really tidy up PAM here too */ + + /* reopen stdin as pipe */ + close(fds[1]); + dup2(fds[0], STDIN_FILENO); + + /* exec binary helper */ + args[0] = x_strdup(CHKPWD_HELPER); + args[1] = x_strdup(user); + + execve(CHKPWD_HELPER, args, envp); + + /* should not get here: exit with error */ + D(("helper binary is not available")); + exit(PAM_AUTHINFO_UNAVAIL); + } else if (child > 0) { + /* wait for child */ + /* if the stored password is NULL */ + if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ + write(fds[1], "nullok\0\0", 8); + } else { + write(fds[1], "nonull\0\0", 8); + } + if (passwd != NULL) { /* send the password to the child */ + write(fds[1], passwd, strlen(passwd)+1); + passwd = NULL; + } else { + write(fds[1], "", 1); /* blank password */ + } + close(fds[0]); /* close here to avoid possible SIGPIPE above */ + close(fds[1]); + (void) waitpid(child, &retval, 0); /* wait for helper to complete */ + retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR; + } else { + D(("fork failed")); + retval = PAM_AUTH_ERR; + } + + D(("returning %d", retval)); + return retval; +} + +int _unix_verify_password(pam_handle_t * pamh, const char *name + ,const char *p, unsigned int ctrl) +{ + struct passwd *pwd = NULL; + struct spwd *spwdent = NULL; + char *salt = NULL; + char *pp = NULL; + char *data_name; + int retval; + + D(("called")); + +#ifdef HAVE_PAM_FAIL_DELAY + if (off(UNIX_NODELAY, ctrl)) { + D(("setting delay")); + (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */ + } +#endif + + /* locate the entry for this user */ + + D(("locating user's record")); + + /* UNIX passwords area */ + pwd = getpwnam(name); /* Get password file entry... */ + + if (pwd != NULL) { + if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) + { /* NIS+ */ + uid_t save_euid, save_uid; + + save_euid = geteuid(); + save_uid = getuid(); + if (save_uid == pwd->pw_uid) + setreuid( save_euid, save_uid ); + else { + setreuid( 0, -1 ); + if (setreuid( -1, pwd->pw_uid ) == -1) { + setreuid( -1, 0 ); + setreuid( 0, -1 ); + if(setreuid( -1, pwd->pw_uid ) == -1) + return PAM_CRED_INSUFFICIENT; + } + } + + spwdent = getspnam( name ); + if (save_uid == pwd->pw_uid) + setreuid( save_uid, save_euid ); + else { + if (setreuid( -1, 0 ) == -1) + setreuid( save_uid, -1 ); + setreuid( -1, save_euid ); + } + } else if (strcmp(pwd->pw_passwd, "x") == 0) { + /* + * ...and shadow password file entry for this user, + * if shadowing is enabled + */ + spwdent = getspnam(name); + } + if (spwdent) + salt = x_strdup(spwdent->sp_pwdp); + else + salt = x_strdup(pwd->pw_passwd); + } + + data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name)); + if (data_name == NULL) { + _log_err(LOG_CRIT, pamh, "no memory for data-name"); + } else { + strcpy(data_name, FAIL_PREFIX); + strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name); + } + + retval = PAM_SUCCESS; + if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) { + if (geteuid()) { + /* we are not root perhaps this is the reason? Run helper */ + D(("running helper binary")); + retval = _unix_run_helper_binary(pamh, p, ctrl, name); + if (pwd == NULL && !on(UNIX_AUDIT,ctrl) + && retval != PAM_SUCCESS) + { + name = NULL; + } + } else { + D(("user's record unavailable")); + if (on(UNIX_AUDIT, ctrl)) { + /* this might be a typo and the user has given a password + instead of a username. Careful with this. */ + _log_err(LOG_ALERT, pamh, + "check pass; user (%s) unknown", name); + } else { + name = NULL; + _log_err(LOG_ALERT, pamh, + "check pass; user unknown"); + } + p = NULL; + retval = PAM_AUTHINFO_UNAVAIL; + } + } else { + if (!strlen(salt)) { + /* the stored password is NULL */ + if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ + D(("user has empty password - access granted")); + retval = PAM_SUCCESS; + } else { + D(("user has empty password - access denied")); + retval = PAM_AUTH_ERR; + } + } else if (!p) { + retval = PAM_AUTH_ERR; + } else { + if (!strncmp(salt, "$1$", 3)) { + pp = Goodcrypt_md5(p, salt); + if (strcmp(pp, salt) != 0) { + _pam_delete(pp); + pp = Brokencrypt_md5(p, salt); + } + } else { + pp = bigcrypt(p, salt); + } + p = NULL; /* no longer needed here */ + + /* the moment of truth -- do we agree with the password? */ + D(("comparing state of pp[%s] and salt[%s]", pp, salt)); + + /* + * Note, we are comparing the bigcrypt of the password with + * the contents of the password field. If the latter was + * encrypted with regular crypt (and not bigcrypt) it will + * have been truncated for storage relative to the output + * of bigcrypt here. As such we need to compare only the + * stored string with the subset of bigcrypt's result. + * Bug 521314: The strncmp comparison is for legacy support. + */ + if (strncmp(pp, salt, strlen(salt)) == 0) { + retval = PAM_SUCCESS; + } else { + retval = PAM_AUTH_ERR; + } + } + } + + if (retval == PAM_SUCCESS) { + if (data_name) /* reset failures */ + pam_set_data(pamh, data_name, NULL, _cleanup_failures); + } else { + if (data_name != NULL) { + struct _pam_failed_auth *new = NULL; + const struct _pam_failed_auth *old = NULL; + + /* get a failure recorder */ + + new = (struct _pam_failed_auth *) + malloc(sizeof(struct _pam_failed_auth)); + + if (new != NULL) { + + new->user = x_strdup(name ? name : ""); + new->uid = getuid(); + new->euid = geteuid(); + new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : ""); + + /* any previous failures for this user ? */ + pam_get_data(pamh, data_name, (const void **) &old); + + if (old != NULL) { + new->count = old->count + 1; + if (new->count >= UNIX_MAX_RETRIES) { + retval = PAM_MAXTRIES; + } + } else { + const char *service=NULL; + const char *ruser=NULL; + const char *rhost=NULL; + const char *tty=NULL; + + (void) pam_get_item(pamh, PAM_SERVICE, + (const void **)&service); + (void) pam_get_item(pamh, PAM_RUSER, + (const void **)&ruser); + (void) pam_get_item(pamh, PAM_RHOST, + (const void **)&rhost); + (void) pam_get_item(pamh, PAM_TTY, + (const void **)&tty); + + _log_err(LOG_NOTICE, pamh, + "authentication failure; " + "logname=%s uid=%d euid=%d " + "tty=%s ruser=%s rhost=%s " + "%s%s", + new->name, new->uid, new->euid, + tty ? tty : "", + ruser ? ruser : "", + rhost ? rhost : "", + (new->user && new->user[0] != '\0') + ? " user=" : "", + new->user + ); + new->count = 1; + } + + pam_set_data(pamh, data_name, new, _cleanup_failures); + + } else { + _log_err(LOG_CRIT, pamh, + "no memory for failure recorder"); + } + } + } + + if (data_name) + _pam_delete(data_name); + if (salt) + _pam_delete(salt); + if (pp) + _pam_delete(pp); + + D(("done [%d].", retval)); + + return retval; +} + +/* + * obtain a password from the user + */ + +int _unix_read_password(pam_handle_t * pamh + ,unsigned int ctrl + ,const char *comment + ,const char *prompt1 + ,const char *prompt2 + ,const char *data_name + ,const char **pass) +{ + int authtok_flag; + int retval; + char *token; + + D(("called")); + + /* + * make sure nothing inappropriate gets returned + */ + + *pass = token = NULL; + + /* + * which authentication token are we getting? + */ + + authtok_flag = on(UNIX__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; + + /* + * should we obtain the password from a PAM item ? + */ + + if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) { + retval = pam_get_item(pamh, authtok_flag, (const void **) pass); + if (retval != PAM_SUCCESS) { + /* very strange. */ + _log_err(LOG_ALERT, pamh + ,"pam_get_item returned error to unix-read-password" + ); + return retval; + } else if (*pass != NULL) { /* we have a password! */ + return PAM_SUCCESS; + } else if (on(UNIX_USE_FIRST_PASS, ctrl)) { + return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ + } else if (on(UNIX_USE_AUTHTOK, ctrl) + && off(UNIX__OLD_PASSWD, ctrl)) { + return PAM_AUTHTOK_RECOVER_ERR; + } + } + /* + * getting here implies we will have to get the password from the + * user directly. + */ + + { + struct pam_message msg[3], *pmsg[3]; + struct pam_response *resp; + int i, replies; + + /* prepare to converse */ + + if (comment != NULL && off(UNIX__QUIET, ctrl)) { + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_TEXT_INFO; + msg[0].msg = comment; + i = 1; + } else { + i = 0; + } + + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = prompt1; + replies = 1; + + if (prompt2 != NULL) { + pmsg[i] = &msg[i]; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + msg[i++].msg = prompt2; + ++replies; + } + /* so call the conversation expecting i responses */ + resp = NULL; + retval = converse(pamh, ctrl, i, pmsg, &resp); + + if (resp != NULL) { + + /* interpret the response */ + + if (retval == PAM_SUCCESS) { /* a good conversation */ + + token = x_strdup(resp[i - replies].resp); + if (token != NULL) { + if (replies == 2) { + + /* verify that password entered correctly */ + if (!resp[i - 1].resp + || strcmp(token, resp[i - 1].resp)) { + _pam_delete(token); /* mistyped */ + retval = PAM_AUTHTOK_RECOVER_ERR; + _make_remark(pamh, ctrl + ,PAM_ERROR_MSG, MISTYPED_PASS); + } + } + } else { + _log_err(LOG_NOTICE, pamh + ,"could not recover authentication token"); + } + + } + /* + * tidy up the conversation (resp_retcode) is ignored + * -- what is it for anyway? AGM + */ + + _pam_drop_reply(resp, i); + + } else { + retval = (retval == PAM_SUCCESS) + ? PAM_AUTHTOK_RECOVER_ERR : retval; + } + } + + if (retval != PAM_SUCCESS) { + if (on(UNIX_DEBUG, ctrl)) + _log_err(LOG_DEBUG, pamh, + "unable to obtain a password"); + return retval; + } + /* 'token' is the entered password */ + + if (off(UNIX_NOT_SET_PASS, ctrl)) { + + /* we store this password as an item */ + + retval = pam_set_item(pamh, authtok_flag, token); + _pam_delete(token); /* clean it up */ + if (retval != PAM_SUCCESS + || (retval = pam_get_item(pamh, authtok_flag + ,(const void **) pass)) + != PAM_SUCCESS) { + + *pass = NULL; + _log_err(LOG_CRIT, pamh, "error manipulating password"); + return retval; + + } + } else { + /* + * then store it as data specific to this module. pam_end() + * will arrange to clean it up. + */ + + retval = pam_set_data(pamh, data_name, (void *) token, _cleanup); + if (retval != PAM_SUCCESS) { + _log_err(LOG_CRIT, pamh + ,"error manipulating password data [%s]" + ,pam_strerror(pamh, retval)); + _pam_delete(token); + return retval; + } + *pass = token; + token = NULL; /* break link to password */ + } + + return PAM_SUCCESS; +} + +/* ****************************************************************** * + * Copyright (c) Jan Rêkorajski 1999. + * Copyright (c) Andrew G. Morgan 1996-8. + * Copyright (c) Alex O. Yuriev, 1996. + * Copyright (c) Cristian Gafton 1996. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_unix/support.h b/Linux-PAM/modules/pam_unix/support.h new file mode 100644 index 00000000..368a4e8f --- /dev/null +++ b/Linux-PAM/modules/pam_unix/support.h @@ -0,0 +1,144 @@ +/* + * $Id: support.h,v 1.1.1.1 2001/04/29 04:17:41 hartmans Exp $ + */ + +#ifndef _PAM_UNIX_SUPPORT_H +#define _PAM_UNIX_SUPPORT_H + + +/* + * here is the string to inform the user that the new passwords they + * typed were not the same. + */ + +#define MISTYPED_PASS "Sorry, passwords do not match" + +/* type definition for the control options */ + +typedef struct { + const char *token; + unsigned int mask; /* shall assume 32 bits of flags */ + unsigned int flag; +} UNIX_Ctrls; + +/* + * macro to determine if a given flag is on + */ + +#define on(x,ctrl) (unix_args[x].flag & ctrl) + +/* + * macro to determine that a given flag is NOT on + */ + +#define off(x,ctrl) (!on(x,ctrl)) + +/* + * macro to turn on/off a ctrl flag manually + */ + +#define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag) +#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag)) + +/* the generic mask */ + +#define _ALL_ON_ (~0U) + +/* end of macro definitions definitions for the control flags */ + +/* ****************************************************************** * + * ctrl flags proper.. + */ + +/* + * here are the various options recognized by the unix module. They + * are enumerated here and then defined below. Internal arguments are + * given NULL tokens. + */ + +#define UNIX__OLD_PASSWD 0 /* internal */ +#define UNIX__VERIFY_PASSWD 1 /* internal */ +#define UNIX__IAMROOT 2 /* internal */ + +#define UNIX_AUDIT 3 /* print more things than debug.. + some information may be sensitive */ +#define UNIX_USE_FIRST_PASS 4 +#define UNIX_TRY_FIRST_PASS 5 +#define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */ + +#define UNIX__PRELIM 7 /* internal */ +#define UNIX__UPDATE 8 /* internal */ +#define UNIX__NONULL 9 /* internal */ +#define UNIX__QUIET 10 /* internal */ +#define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */ +#define UNIX_SHADOW 12 /* signal shadow on */ +#define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */ +#define UNIX__NULLOK 14 /* Null token ok */ +#define UNIX_DEBUG 15 /* send more info to syslog(3) */ +#define UNIX_NODELAY 16 /* admin does not want a fail-delay */ +#define UNIX_NIS 17 /* wish to use NIS for pwd */ +#define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */ +#define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */ +#define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */ +/* -------------- */ +#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */ + + +static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = +{ +/* symbol token name ctrl mask ctrl * + * ----------------------- ------------------- --------------------- -------- */ + +/* UNIX__OLD_PASSWD */ {NULL, _ALL_ON_, 01}, +/* UNIX__VERIFY_PASSWD */ {NULL, _ALL_ON_, 02}, +/* UNIX__IAMROOT */ {NULL, _ALL_ON_, 04}, +/* UNIX_AUDIT */ {"audit", _ALL_ON_, 010}, +/* UNIX_USE_FIRST_PASS */ {"use_first_pass", _ALL_ON_^(060), 020}, +/* UNIX_TRY_FIRST_PASS */ {"try_first_pass", _ALL_ON_^(060), 040}, +/* UNIX_NOT_SET_PASS */ {"not_set_pass", _ALL_ON_, 0100}, +/* UNIX__PRELIM */ {NULL, _ALL_ON_^(0600), 0200}, +/* UNIX__UPDATE */ {NULL, _ALL_ON_^(0600), 0400}, +/* UNIX__NONULL */ {NULL, _ALL_ON_, 01000}, +/* UNIX__QUIET */ {NULL, _ALL_ON_, 02000}, +/* UNIX_USE_AUTHTOK */ {"use_authtok", _ALL_ON_, 04000}, +/* UNIX_SHADOW */ {"shadow", _ALL_ON_, 010000}, +/* UNIX_MD5_PASS */ {"md5", _ALL_ON_^(0400000), 020000}, +/* UNIX__NULLOK */ {"nullok", _ALL_ON_^(01000), 0}, +/* UNIX_DEBUG */ {"debug", _ALL_ON_, 040000}, +/* UNIX_NODELAY */ {"nodelay", _ALL_ON_, 0100000}, +/* UNIX_NIS */ {"nis", _ALL_ON_^(010000), 0200000}, +/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000}, +/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000}, +/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000}, +}; + +#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) + + +/* use this to free strings. ESPECIALLY password strings */ + +#define _pam_delete(xx) \ +{ \ + _pam_overwrite(xx); \ + _pam_drop(xx); \ +} + +extern char *PAM_getlogin(void); +extern void _log_err(int err, pam_handle_t *pamh, const char *format,...); +extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl + ,int type, const char *text); +extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc, + const char **argv); +extern int _unix_blankpasswd(unsigned int ctrl, const char *name); +extern int _unix_verify_password(pam_handle_t * pamh, const char *name + ,const char *p, unsigned int ctrl); +extern int _unix_read_password(pam_handle_t * pamh + ,unsigned int ctrl + ,const char *comment + ,const char *prompt1 + ,const char *prompt2 + ,const char *data_name + ,const char **pass); + +#endif /* _PAM_UNIX_SUPPORT_H */ + diff --git a/Linux-PAM/modules/pam_unix/unix_chkpwd.c b/Linux-PAM/modules/pam_unix/unix_chkpwd.c new file mode 100644 index 00000000..6188435f --- /dev/null +++ b/Linux-PAM/modules/pam_unix/unix_chkpwd.c @@ -0,0 +1,329 @@ +/* + * $Id: unix_chkpwd.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * + * This program is designed to run setuid(root) or with sufficient + * privilege to read all of the unix password databases. It is designed + * to provide a mechanism for the current user (defined by this + * process' uid) to verify their own password. + * + * The password is read from the standard input. The exit status of + * this program indicates whether the user is authenticated or not. + * + * Copyright information is located at the end of the file. + * + */ + +#include <security/_pam_aconf.h> + +#ifdef MEMORY_DEBUG +# undef exit +# undef strdup +# undef free +#endif /* MEMORY_DEBUG */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <shadow.h> +#include <signal.h> + +#define MAXPASS 200 /* the maximum length of a password */ + +#include <security/_pam_macros.h> + +#include "md5.h" + +extern char *crypt(const char *key, const char *salt); +extern char *bigcrypt(const char *key, const char *salt); + +#define UNIX_PASSED 0 +#define UNIX_FAILED 1 + +/* syslogging function for errors and other information */ + +static void _log_err(int err, const char *format,...) +{ + va_list args; + + va_start(args, format); + openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static void su_sighandler(int sig) +{ + if (sig > 0) { + _log_err(LOG_NOTICE, "caught signal %d.", sig); + exit(sig); + } +} + +static void setup_signals(void) +{ + struct sigaction action; /* posix signal structure */ + + /* + * Setup signal handlers + */ + (void) memset((void *) &action, 0, sizeof(action)); + action.sa_handler = su_sighandler; + action.sa_flags = SA_RESETHAND; + (void) sigaction(SIGILL, &action, NULL); + (void) sigaction(SIGTRAP, &action, NULL); + (void) sigaction(SIGBUS, &action, NULL); + (void) sigaction(SIGSEGV, &action, NULL); + action.sa_handler = SIG_IGN; + action.sa_flags = 0; + (void) sigaction(SIGTERM, &action, NULL); + (void) sigaction(SIGHUP, &action, NULL); + (void) sigaction(SIGINT, &action, NULL); + (void) sigaction(SIGQUIT, &action, NULL); +} + +static int _unix_verify_password(const char *name, const char *p, int opt) +{ + struct passwd *pwd = NULL; + struct spwd *spwdent = NULL; + char *salt = NULL; + char *pp = NULL; + int retval = UNIX_FAILED; + + /* UNIX passwords area */ + setpwent(); + pwd = getpwnam(name); /* Get password file entry... */ + endpwent(); + if (pwd != NULL) { + if (strcmp(pwd->pw_passwd, "x") == 0) { + /* + * ...and shadow password file entry for this user, + * if shadowing is enabled + */ + setspent(); + spwdent = getspnam(name); + endspent(); + if (spwdent != NULL) + salt = x_strdup(spwdent->sp_pwdp); + else + pwd = NULL; + } else { + if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ + uid_t save_uid; + + save_uid = geteuid(); + seteuid(pwd->pw_uid); + spwdent = getspnam(name); + seteuid(save_uid); + + salt = x_strdup(spwdent->sp_pwdp); + } else { + salt = x_strdup(pwd->pw_passwd); + } + } + } + if (pwd == NULL || salt == NULL) { + _log_err(LOG_ALERT, "check pass; user unknown"); + p = NULL; + return retval; + } + + if (strlen(salt) == 0) + return (opt == 0) ? UNIX_FAILED : UNIX_PASSED; + + /* the moment of truth -- do we agree with the password? */ + retval = UNIX_FAILED; + if (!strncmp(salt, "$1$", 3)) { + pp = Goodcrypt_md5(p, salt); + if (strcmp(pp, salt) == 0) { + retval = UNIX_PASSED; + } else { + pp = Brokencrypt_md5(p, salt); + if (strcmp(pp, salt) == 0) + retval = UNIX_PASSED; + } + } else { + pp = bigcrypt(p, salt); + /* + * Note, we are comparing the bigcrypt of the password with + * the contents of the password field. If the latter was + * encrypted with regular crypt (and not bigcrypt) it will + * have been truncated for storage relative to the output + * of bigcrypt here. As such we need to compare only the + * stored string with the subset of bigcrypt's result. + * Bug 521314: the strncmp comparison is for legacy support. + */ + if (strncmp(pp, salt, strlen(salt)) == 0) { + retval = UNIX_PASSED; + } + } + p = NULL; /* no longer needed here */ + + /* clean up */ + { + char *tp = pp; + if (pp != NULL) { + while (tp && *tp) + *tp++ = '\0'; + free(pp); + } + pp = tp = NULL; + } + + return retval; +} + +static char *getuidname(uid_t uid) +{ + struct passwd *pw; + static char username[32]; + + pw = getpwuid(uid); + if (pw == NULL) + return NULL; + + strncpy(username, pw->pw_name, sizeof(username)); + username[sizeof(username) - 1] = '\0'; + + return username; +} + +int main(int argc, char *argv[]) +{ + char pass[MAXPASS + 1]; + char option[8]; + int npass, opt; + int force_failure = 0; + int retval = UNIX_FAILED; + char *user; + + /* + * Catch or ignore as many signal as possible. + */ + setup_signals(); + + /* + * we establish that this program is running with non-tty stdin. + * this is to discourage casual use. It does *NOT* prevent an + * intruder from repeatadly running this program to determine the + * password of the current user (brute force attack, but one for + * which the attacker must already have gained access to the user's + * account). + */ + + if (isatty(STDIN_FILENO)) { + + _log_err(LOG_NOTICE + ,"inappropriate use of Unix helper binary [UID=%d]" + ,getuid()); + fprintf(stderr + ,"This binary is not designed for running in this way\n" + "-- the system administrator has been informed\n"); + sleep(10); /* this should discourage/annoy the user */ + return UNIX_FAILED; + } + + /* + * determine the current user's name is + */ + user = getuidname(getuid()); + if (argc == 2) { + /* if the caller specifies the username, verify that user + matches it */ + if (strcmp(user, argv[1])) { + force_failure = 1; + } + } + + /* read the nullok/nonull option */ + + npass = read(STDIN_FILENO, option, 8); + + if (npass < 0) { + _log_err(LOG_DEBUG, "no option supplied"); + return UNIX_FAILED; + } else { + option[7] = '\0'; + if (strncmp(option, "nullok", 8) == 0) + opt = 1; + else + opt = 0; + } + + /* read the password from stdin (a pipe from the pam_unix module) */ + + npass = read(STDIN_FILENO, pass, MAXPASS); + + if (npass < 0) { /* is it a valid password? */ + + _log_err(LOG_DEBUG, "no password supplied"); + + } else if (npass >= MAXPASS) { + + _log_err(LOG_DEBUG, "password too long"); + + } else { + if (npass == 0) { + /* the password is NULL */ + + retval = _unix_verify_password(user, NULL, opt); + + } else { + /* does pass agree with the official one? */ + + pass[npass] = '\0'; /* NUL terminate */ + retval = _unix_verify_password(user, pass, opt); + + } + } + + memset(pass, '\0', MAXPASS); /* clear memory of the password */ + + /* return pass or fail */ + + if ((retval != UNIX_PASSED) || force_failure) { + return UNIX_FAILED; + } else { + return UNIX_PASSED; + } +} + +/* + * Copyright (c) Andrew G. Morgan, 1996. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_unix/yppasswd.h b/Linux-PAM/modules/pam_unix/yppasswd.h new file mode 100644 index 00000000..6b414be0 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/yppasswd.h @@ -0,0 +1,51 @@ +/* + * yppasswdd + * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de> + * + * This program is covered by the GNU General Public License, version 2. + * It is provided in the hope that it is useful. However, the author + * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details. + * + * This file was generated automatically by rpcgen from yppasswd.x, and + * editied manually. + */ + +#ifndef _YPPASSWD_H_ +#define _YPPASSWD_H_ + +#define YPPASSWDPROG ((u_long)100009) +#define YPPASSWDVERS ((u_long)1) +#define YPPASSWDPROC_UPDATE ((u_long)1) + +/* + * The password struct passed by the update call. I renamed it to + * xpasswd to avoid a type clash with the one defined in <pwd.h>. + */ +#ifndef __sgi +typedef struct xpasswd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +} xpasswd; + +#else +#include <pwd.h> +typedef struct xpasswd xpasswd; +#endif + +/* The updated password information, plus the old password. + */ +typedef struct yppasswd { + char *oldpass; + xpasswd newpw; +} yppasswd; + +/* XDR encoding/decoding routines */ +bool_t xdr_xpasswd(XDR * xdrs, xpasswd * objp); +bool_t xdr_yppasswd(XDR * xdrs, yppasswd * objp); + +#endif /* _YPPASSWD_H_ */ diff --git a/Linux-PAM/modules/pam_unix/yppasswd_xdr.c b/Linux-PAM/modules/pam_unix/yppasswd_xdr.c new file mode 100644 index 00000000..b1a60b4c --- /dev/null +++ b/Linux-PAM/modules/pam_unix/yppasswd_xdr.c @@ -0,0 +1,38 @@ +/* + * yppasswdd + * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de> + * + * This program is covered by the GNU General Public License, version 2. + * It is provided in the hope that it is useful. However, the author + * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details. + * + * This file was generated automatically by rpcgen from yppasswd.x, and + * editied manually. + */ + +#include <security/_pam_aconf.h> + +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#include "yppasswd.h" + +bool_t +xdr_xpasswd(XDR * xdrs, xpasswd * objp) +{ + return xdr_string(xdrs, &objp->pw_name, ~0) + && xdr_string(xdrs, &objp->pw_passwd, ~0) + && xdr_int(xdrs, &objp->pw_uid) + && xdr_int(xdrs, &objp->pw_gid) + && xdr_string(xdrs, &objp->pw_gecos, ~0) + && xdr_string(xdrs, &objp->pw_dir, ~0) + && xdr_string(xdrs, &objp->pw_shell, ~0); +} + + +bool_t +xdr_yppasswd(XDR * xdrs, yppasswd * objp) +{ + return xdr_string(xdrs, &objp->oldpass, ~0) + && xdr_xpasswd(xdrs, &objp->newpw); +} diff --git a/Linux-PAM/modules/pam_userdb/Makefile b/Linux-PAM/modules/pam_userdb/Makefile new file mode 100644 index 00000000..bb774ddb --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/Makefile @@ -0,0 +1,37 @@ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). + +# $Id: Makefile,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ +# Created by Cristian Gafton <gafton@redhat.com> + +include ../../Make.Rules + +TITLE=pam_userdb + +ifeq ($(HAVE_NDBM_H),yes) + WHICH_DB=ndbm + ifeq ($(HAVE_LIBNDBM),yes) + MODULE_SIMPLE_EXTRALIBS = -lndbm + endif +else +ifeq ($(HAVE_LIBDB),yes) + WHICH_DB=db + MODULE_SIMPLE_EXTRALIBS = -ldb +else + WHICH_DB=none +endif +endif + +ifeq ($(WHICH_DB),none) + +include ../dont_makefile + +else + +MODULE_SIMPLE_EXTRAFILES = conv + +include ../Simple.Rules + +endif diff --git a/Linux-PAM/modules/pam_userdb/README b/Linux-PAM/modules/pam_userdb/README new file mode 100644 index 00000000..f4423781 --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/README @@ -0,0 +1,30 @@ +pam_userdb: + Look up users in a .db database and verify their password against + what is contained in that database. + +RECOGNIZED ARGUMENTS: + debug write a message to syslog indicating success or + failure. + + db=[path] use the [path] database for performing lookup. There + is no default; the module will return PAM_IGNORE if + no database is provided. + + icase make the password verification to be case insensitive + (ie when working with registration numbers and such) + + dump dump all the entries in the database to the log (eek, + don't do this by default!) + +MODULE SERVICES PROVIDED: + auth _authetication and _setcred (blank) + +EXAMPLE USE: + auth sufficient pam_userdb.so icase db=/tmp/dbtest.db + +AUTHOR: + Cristian Gafton <gafton@redhat.com> + + + +$Id: README,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ diff --git a/Linux-PAM/modules/pam_userdb/conv.c b/Linux-PAM/modules/pam_userdb/conv.c new file mode 100644 index 00000000..0f13d03a --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/conv.c @@ -0,0 +1,125 @@ +/* + * Conversation related functions + */ + +/* $Id */ +/* Copyright at the end of the file */ + +#define _BSD_SOURCE + +#include <stdlib.h> +#include <string.h> + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> + +#include "pam_userdb.h" + +/* + * dummy conversation function sending exactly one prompt + * and expecting exactly one response from the other party + */ +static int converse(pam_handle_t *pamh, + struct pam_message **message, + struct pam_response **response) +{ + int retval; + const struct pam_conv *conv; + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ; + if (retval == PAM_SUCCESS) + retval = conv->conv(1, (const struct pam_message **)message, + response, conv->appdata_ptr); + + return retval; /* propagate error status */ +} + + +static char *_pam_delete(register char *xx) +{ + _pam_overwrite(xx); + _pam_drop(xx); + return NULL; +} + +/* + * This is a conversation function to obtain the user's password + */ +int conversation(pam_handle_t *pamh) +{ + struct pam_message msg[2],*pmsg[2]; + struct pam_response *resp; + int retval; + char * token = NULL; + + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = "Password: "; + + /* so call the conversation expecting i responses */ + resp = NULL; + retval = converse(pamh, pmsg, &resp); + + if (resp != NULL) { + const char * item; + /* interpret the response */ + if (retval == PAM_SUCCESS) { /* a good conversation */ + token = x_strdup(resp[0].resp); + if (token == NULL) { + return PAM_AUTHTOK_RECOVER_ERR; + } + } + + /* set the auth token */ + retval = pam_set_item(pamh, PAM_AUTHTOK, token); + token = _pam_delete(token); /* clean it up */ + if ( (retval != PAM_SUCCESS) || + (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item)) + != PAM_SUCCESS ) { + return retval; + } + + _pam_drop_reply(resp, 1); + } else { + retval = (retval == PAM_SUCCESS) + ? PAM_AUTHTOK_RECOVER_ERR:retval ; + } + + return retval; +} + +/* + * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_userdb/create.pl b/Linux-PAM/modules/pam_userdb/create.pl new file mode 100644 index 00000000..2668ef4a --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/create.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# this program creates a database in ARGV[1] from pairs given on +# stdandard input +# +# $Id: create.pl,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ + +use DB_File; + +my $database = $ARGV[0]; +die "Use: check,pl <database>\n" unless ($database); +print "Using database: $database\n"; + +my %lusers = (); + +tie %lusers, 'DB_File', $database, O_RDWR|O_CREAT, 0644, $DB_HASH ; +while (<STDIN>) { + my ($user, $pass) = split; + + $lusers{$user} = $pass; +} +untie %lusers; + + diff --git a/Linux-PAM/modules/pam_userdb/pam_userdb.c b/Linux-PAM/modules/pam_userdb/pam_userdb.c new file mode 100644 index 00000000..337d217b --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/pam_userdb.c @@ -0,0 +1,307 @@ +/* pam_userdb module */ + +/* + * $Id: pam_userdb.c,v 1.1.1.2 2002/09/15 20:09:03 hartmans Exp $ + * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 + * See the end of the file for Copyright Information + */ + +#include <security/_pam_aconf.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "pam_userdb.h" + +#ifdef HAVE_NDBM_H +# include <ndbm.h> +#else +# ifdef HAVE_DB_H +# define DB_DBM_HSEARCH 1 /* use the dbm interface */ +# include <db.h> +# else +# error "failed to find a libdb or equivalent" +# endif +#endif + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT + +#include <security/pam_modules.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +char * database = NULL; +static int ctrl = 0; + +static int _pam_parse(int argc, const char **argv) +{ + /* step through arguments */ + for (ctrl = 0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strcasecmp(*argv, "icase")) + ctrl |= PAM_ICASE_ARG; + else if (!strcasecmp(*argv, "dump")) + ctrl |= PAM_DUMP_ARG; + else if (!strncasecmp(*argv,"db=", 3)) { + database = strdup((*argv) + 3); + if (database == NULL) + _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", + *argv); + } else { + _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); + } + } + + return ctrl; +} + + +/* + * Looks up an user name in a database and checks the password + * + * return values: + * 1 = User not found + * 0 = OK + * -1 = Password incorrect + * -2 = System error + */ +static int user_lookup(const char *user, const char *pass) +{ + DBM *dbm; + datum key, data; + + /* Open the DB file. */ + dbm = dbm_open(database, O_RDONLY, 0644); + if (dbm == NULL) { + _pam_log(LOG_ERR, "user_lookup: could not open database `%s'", + database); + return -2; + } + + if (ctrl &PAM_DUMP_ARG) { + _pam_log(LOG_INFO, "Database dump:"); + for (key = dbm_firstkey(dbm); key.dptr != NULL; + key = dbm_nextkey(dbm)) { + data = dbm_fetch(dbm, key); + _pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'", + key.dsize, key.dptr, data.dsize, data.dptr); + } + } + /* do some more init work */ + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.dptr = x_strdup(user); + key.dsize = strlen(user); + user = NULL; + + if (key.dptr) { + data = dbm_fetch(dbm, key); + memset(key.dptr, 0, key.dsize); + free(key.dptr); + } + + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "password in database is [%p]`%s', len is %d", + data.dptr, (char *) data.dptr, data.dsize); + } + + if (data.dptr != NULL) { + int compare = 0; + + if (strlen(pass) != data.dsize) { + compare = 1; + } else if (ctrl & PAM_ICASE_ARG) { + compare = strncasecmp(data.dptr, pass, data.dsize); + } else { + compare = strncmp(data.dptr, pass, data.dsize); + } + dbm_close(dbm); + if (compare == 0) + return 0; /* match */ + else + return -1; /* wrong */ + } else { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "error returned by dbm_fetch: %s", + strerror(errno)); + } + dbm_close(dbm); + /* probably we should check dbm_error() here */ + return 1; /* not found */ + } + + /* NOT REACHED */ + return -2; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + const char *username; + const char *password; + int retval = PAM_AUTH_ERR; + + /* parse arguments */ + ctrl = _pam_parse(argc, argv); + + /* Get the username */ + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"can not get the username"); + return PAM_SERVICE_ERR; + } + + /* Converse just to be sure we have the password */ + retval = conversation(pamh); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR, "could not obtain password for `%s'", + username); + return -2; + } + + /* Get the password */ + retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR, "Could not retrive user's password"); + return -2; + } + + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", + username, password); + + /* Now use the username to look up password in the database file */ + retval = user_lookup(username, password); + switch (retval) { + case -2: + /* some sort of system error. The log was already printed */ + return PAM_SERVICE_ERR; + case -1: + /* incorrect password */ + _pam_log(LOG_WARNING, + "user `%s' denied access (incorrect password)", + username); + return PAM_AUTH_ERR; + case 1: + /* the user does not exist in the database */ + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE, "user `%s' not found in the database", + username); + return PAM_USER_UNKNOWN; + case 0: + /* Otherwise, the authentication looked good */ + _pam_log(LOG_NOTICE, "user '%s' granted acces", username); + return PAM_SUCCESS; + default: + /* we don't know anything about this return value */ + _pam_log(LOG_ERR, + "internal module error (retval = %d, user = `%s'", + retval, username); + return PAM_SERVICE_ERR; + } + + /* should not be reached */ + return PAM_IGNORE; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return PAM_SUCCESS; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_userdb_modstruct = { + "pam_userdb", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* + * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_userdb/pam_userdb.h b/Linux-PAM/modules/pam_userdb/pam_userdb.h new file mode 100644 index 00000000..88a93f0d --- /dev/null +++ b/Linux-PAM/modules/pam_userdb/pam_userdb.h @@ -0,0 +1,61 @@ + +#ifndef _PAM_USERSDB_H +#define _PAM_USERSDB_H +/* $Id: pam_userdb.h,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ */ + +/* Header files */ +#include <security/pam_appl.h> + +/* argument parsing */ +#define PAM_DEBUG_ARG 0x0001 +#define PAM_ICASE_ARG 0x0002 +#define PAM_DUMP_ARG 0x0004 + +/* Useful macros */ +#define x_strdup(s) ( (s) ? strdup(s):NULL ) + +/* The name of the module we are compiling */ +#ifndef MODULE_NAME +#define MODULE_NAME "pam_userdb" +#endif /* MODULE_NAME */ + +/* function prototypes */ +int conversation(pam_handle_t *); + +#endif /* _PAM_USERSDB_H */ + +/* + * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pam_warn/Makefile b/Linux-PAM/modules/pam_warn/Makefile new file mode 100644 index 00000000..657570e6 --- /dev/null +++ b/Linux-PAM/modules/pam_warn/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_warn + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_warn/README b/Linux-PAM/modules/pam_warn/README new file mode 100644 index 00000000..ab128179 --- /dev/null +++ b/Linux-PAM/modules/pam_warn/README @@ -0,0 +1,26 @@ +# $Id: README,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# + +This module is an authentication module that does not authenticate. +Instead it always returns PAM_IGNORE, indicating that it does not want +to affect the authentication process. + +Its purpose is to log a message to the syslog indicating the +pam_item's available at the time it was invoked. It is a diagnostic +tool. + +Recognized arguments: + + <none> + +module services provided: + + auth _authenticate and _setcred (blank) + acct _acct_mgmt [mapped to _authenticate] + session _open_session and + _close_session [mapped to _authenticate ] + password _chauthtok [mapped to _authenticate] + + +Andrew Morgan +1996/11/14 diff --git a/Linux-PAM/modules/pam_warn/pam_warn.c b/Linux-PAM/modules/pam_warn/pam_warn.c new file mode 100644 index 00000000..f84490e8 --- /dev/null +++ b/Linux-PAM/modules/pam_warn/pam_warn.c @@ -0,0 +1,127 @@ +/* pam_warn module */ + +/* + * $Id: pam_warn.c,v 1.1.1.2 2002/09/15 20:09:04 hartmans Exp $ + * + * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 + */ + +#define _BSD_SOURCE + +#include <stdio.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> + +/* some syslogging */ + +#define OBTAIN(item, value, default_value) do { \ + (void) pam_get_item(pamh, item, (const void **) &value); \ + value = value ? value : default_value ; \ +} while (0) + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-warn", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static void log_items(pam_handle_t *pamh, const char *function) +{ + const char *service=NULL, *user=NULL, *terminal=NULL, + *rhost=NULL, *ruser=NULL; + + OBTAIN(PAM_SERVICE, service, "<unknown>"); + OBTAIN(PAM_TTY, terminal, "<unknown>"); + OBTAIN(PAM_USER, user, "<unknown>"); + OBTAIN(PAM_RUSER, ruser, "<unknown>"); + OBTAIN(PAM_RHOST, rhost, "<unknown>"); + + _pam_log(LOG_NOTICE, "function=[%s] service=[%s] terminal=[%s] user=[%s]" + " ruser=[%s] rhost=[%s]\n", + function, service, terminal, user, ruser, rhost); +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +/* password updating functions */ + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +PAM_EXTERN int +pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + log_items(pamh, __FUNCTION__); + return PAM_IGNORE; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_warn_modstruct = { + "pam_warn", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok, +}; + +#endif + +/* end of module definition */ diff --git a/Linux-PAM/modules/pam_wheel/Makefile b/Linux-PAM/modules/pam_wheel/Makefile new file mode 100644 index 00000000..e4f8a450 --- /dev/null +++ b/Linux-PAM/modules/pam_wheel/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_wheel + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_wheel/README b/Linux-PAM/modules/pam_wheel/README new file mode 100644 index 00000000..336bb31e --- /dev/null +++ b/Linux-PAM/modules/pam_wheel/README @@ -0,0 +1,33 @@ + +pam_wheel: + only permit root authentication too members of wheel group + +RECOGNIZED ARGUMENTS: + debug write a message to syslog indicating success or + failure. + + use_uid the check for wheel membership will be done against + the current uid instead of the original one + (useful when jumping with su from one account to + another for example) + + trust the pam_wheel module will return PAM_SUCCESS instead + of PAM_IGNORE if the user is a member of the wheel + group (thus with a little play stacking the modules + the wheel members may be able to su to root without + being prompted for a passwd). + + deny Reverse the sense of the auth operation: if the user + is trying to get UID 0 access and is a member of the + wheel group, deny access (well, kind of nonsense, but + for use in conjunction with 'group' argument... :-) + + group=xxxx Instead of checking the GID 0 group, use the xxxx + group to perform the authentification. + +MODULE SERVICES PROVIDED: + auth _authetication and _setcred (blank) + +AUTHOR: + Cristian Gafton <gafton@sorosis.ro> + diff --git a/Linux-PAM/modules/pam_wheel/pam_wheel.c b/Linux-PAM/modules/pam_wheel/pam_wheel.c new file mode 100644 index 00000000..d629819f --- /dev/null +++ b/Linux-PAM/modules/pam_wheel/pam_wheel.c @@ -0,0 +1,276 @@ +/* pam_wheel module */ + +/* + * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 + * See the end of the file for Copyright Information + * + * + * 1.2 - added 'deny' and 'group=' options + * 1.1 - added 'trust' option + * 1.0 - the code is working for at least another person, so... :-) + * 0.1 - use vsyslog instead of vfprintf/syslog in _pam_log + * - return PAM_IGNORE on success (take care of sloppy sysadmins..) + * - use pam_get_user instead of pam_get_item(...,PAM_USER,...) + * - a new arg use_uid to auth the current uid instead of the + * initial (logged in) one. + * 0.0 - first release + * + * TODO: + * - try to use make_remark from pam_unix/support.c + * - consider returning on failure PAM_FAIL_NOW if the user is not + * a wheel member. + */ + +#define _BSD_SOURCE + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <stdarg.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH + +#include <security/pam_modules.h> + +/* some syslogging */ + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-Wheel", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +/* checks if a user is on a list of members of the GID 0 group */ + +static int is_on_list(char * const *list, const char *member) +{ + while (*list) { + if (strcmp(*list, member) == 0) + return 1; + list++; + } + return 0; +} + +/* argument parsing */ + +#define PAM_DEBUG_ARG 0x0001 +#define PAM_USE_UID_ARG 0x0002 +#define PAM_TRUST_ARG 0x0004 +#define PAM_DENY_ARG 0x0010 + +static int _pam_parse(int argc, const char **argv, char *use_group, + size_t group_length) +{ + int ctrl=0; + + memset(use_group, '\0', group_length); + + /* step through arguments */ + for (ctrl=0; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strcmp(*argv,"use_uid")) + ctrl |= PAM_USE_UID_ARG; + else if (!strcmp(*argv,"trust")) + ctrl |= PAM_TRUST_ARG; + else if (!strcmp(*argv,"deny")) + ctrl |= PAM_DENY_ARG; + else if (!strncmp(*argv,"group=",6)) + strncpy(use_group,*argv+6,group_length-1); + else { + _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); + } + } + + return ctrl; +} + + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + int ctrl; + const char *username; + char *fromsu; + struct passwd *pwd, *tpwd; + struct group *grp; + int retval = PAM_AUTH_ERR; + char use_group[BUFSIZ]; + + /* Init the optional group */ + bzero(use_group,BUFSIZ); + + ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group)); + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"can not get the username"); + return PAM_SERVICE_ERR; + } + + /* su to a uid 0 account ? */ + pwd = getpwnam(username); + if (!pwd) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"unknown user %s",username); + return PAM_USER_UNKNOWN; + } + + /* Now we know that the username exists, pass on to other modules... + * the call to pam_get_user made this obsolete, so is commented out + * + * pam_set_item(pamh,PAM_USER,(const void *)username); + */ + + /* is this user an UID 0 account ? */ + if(pwd->pw_uid) { + /* no need to check for wheel */ + return PAM_IGNORE; + } + + if (ctrl & PAM_USE_UID_ARG) { + tpwd = getpwuid(getuid()); + if (!tpwd) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"who is running me ?!"); + return PAM_SERVICE_ERR; + } + fromsu = tpwd->pw_name; + } else { + fromsu = getlogin(); + if (!fromsu) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"who is running me ?!"); + return PAM_SERVICE_ERR; + } + } + + if (!use_group[0]) { + if ((grp = getgrnam("wheel")) == NULL) { + grp = getgrgid(0); + } + } else + grp = getgrnam(use_group); + + if (!grp || !grp->gr_mem) { + if (ctrl & PAM_DEBUG_ARG) { + if (!use_group[0]) + _pam_log(LOG_NOTICE,"no members in a GID 0 group"); + else + _pam_log(LOG_NOTICE,"no members in '%s' group",use_group); + } + if (ctrl & PAM_DENY_ARG) + /* if this was meant to deny access to the members + * of this group and the group does not exist, allow + * access + */ + return PAM_IGNORE; + else + return PAM_AUTH_ERR; + } + + if (is_on_list(grp->gr_mem, fromsu)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'", + (ctrl & PAM_DENY_ARG)?"denied":"granted", + fromsu,username); + if (ctrl & PAM_DENY_ARG) + return PAM_PERM_DENIED; + else + if (ctrl & PAM_TRUST_ARG) + return PAM_SUCCESS; + else + return PAM_IGNORE; + } + + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'", + (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username); + if (ctrl & PAM_DENY_ARG) + return PAM_SUCCESS; + else + return PAM_PERM_DENIED; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_wheel_modstruct = { + "pam_wheel", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + NULL, + NULL, + NULL, +}; + +#endif + +/* + * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997 + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Linux-PAM/modules/pammodutil/Makefile b/Linux-PAM/modules/pammodutil/Makefile new file mode 100644 index 00000000..03334326 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/Makefile @@ -0,0 +1,53 @@ +# +# $Id: Makefile,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ +# +# + +include ../../Make.Rules + +LIBNAME=libpammodutil + +# --------------------------------------------- + +dummy: all + +# --------------------------------------------- + +CFLAGS += $(PIC) $(STATIC) $(MOREFLAGS) \ + -DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \ + -DLIBPAM_VERSION_MINOR=$(MINOR_REL) + +# all the object files we care about +LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o + +# static library name +LIBSTATIC = $(LIBNAME).a + +SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ)) + +# --------------------------------------------- +## rules + +all: dirs $(LIBSTATIC) ../../Make.Rules + +dirs: + $(MKDIR) static + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(LIBSTATIC): $(SLIBOBJECTS) + ar cr $@ $(SLIBOBJECTS) + $(RANLIB) $@ + +install: + @echo "at this time, we're not installing $(LIBSTATIC)" + +remove: + @echo "at this time, there is nothing to remove" + +clean: + rm -f a.out core *~ static/*.o + rm -f *.a *.o + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi diff --git a/Linux-PAM/modules/pammodutil/README b/Linux-PAM/modules/pammodutil/README new file mode 100644 index 00000000..bd957247 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/README @@ -0,0 +1,15 @@ +$Id: README,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + +This is a libarary of routines for use by modules. The routines seem +to have a common use for modules, but are not part of libpam and never +will be. They are also a convenient layer of abstraction for providing +thread-safe functions that may require use of pam_handle_t 'data' +items to make their thread-safeness tied to the use of a single +pam_handle_t per thread. + +Functions provided so far are all listed in + + include/security/_pam_modutil.h + +. + diff --git a/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h new file mode 100644 index 00000000..d36fcfa0 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h @@ -0,0 +1,33 @@ +#ifndef _PAM_MODUTIL_H +#define _PAM_MODUTIL_H + +/* + * $Id: _pam_modutil.h,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * + * This file is a list of handy libc wrappers that attempt to provide some + * thread-safe and other convenient functionality to modules in a form that + * is common, but not dynamically linked with yet another dynamic pam + * library extension. + * + * A number of these functions reserve space in a pam_[sg]et_data item. + * In all cases, the name of the item is prefixed with "_pammodutil_*". + * + * On systems that simply can't support thread safe programming, these + * functions don't support it either - sorry. + * + * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> + */ + +#include <pwd.h> +#include <sys/types.h> + +extern struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, + const char *user); + +extern struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, + uid_t uid); + +extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, + int error_status); + +#endif /* _PAM_MODUTIL_H */ diff --git a/Linux-PAM/modules/pammodutil/modutil_cleanup.c b/Linux-PAM/modules/pammodutil/modutil_cleanup.c new file mode 100644 index 00000000..76662133 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_cleanup.c @@ -0,0 +1,16 @@ +/* + * $Id: modutil_cleanup.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * + * This function provides a common pam_set_data() friendly version of free(). + */ + +#include "pammodutil.h" + +void _pammodutil_cleanup(pam_handle_t *pamh, void *data, int error_status) +{ + if (data) { + /* junk it */ + (void) free(data); + } +} + diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c new file mode 100644 index 00000000..e3a8f270 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c @@ -0,0 +1,80 @@ +/* + * $Id: modutil_getpwnam.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * + * This function provides a thread safer version of getpwnam() for use + * with PAM modules that care about this sort of thing. + * + * XXX - or at least it should provide a thread-safe alternative. + */ + +#include "pammodutil.h" + +#include <pwd.h> +#include <stdlib.h> + +struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user) +{ +#ifdef HAVE_GETPWNAM_R + + void *buffer=NULL; + size_t length = PWD_INITIAL_LENGTH; + + do { + int status; + void *new_buffer; + struct passwd *result = NULL; + + new_buffer = realloc(buffer, sizeof(struct passwd) + length); + if (new_buffer == NULL) { + + D(("out of memory")); + + /* no memory for the user - so delete the memory */ + if (buffer) { + free(buffer); + } + return NULL; + } + buffer = new_buffer; + + /* make the re-entrant call to get the pwd structure */ + status = getpwnam_r(user, buffer, + sizeof(struct passwd) + (char *) buffer, + length, &result); + if (!status && result) { + status = pam_set_data(pamh, "_pammodutil_getpwnam", result, + _pammodutil_cleanup); + if (status == PAM_SUCCESS) { + D(("success")); + return result; + } + + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + + free(buffer); + return NULL; + + } + + length <<= 1; + + } while (length < PWD_ABSURD_PWD_LENGTH); + + D(("pwd structure took %u bytes or so of memory", + length+sizeof(struct passwd))); + + free(buffer); + return NULL; + +#else /* ie. ifndef HAVE_GETPWNAM_R */ + + /* + * Sorry, there does not appear to be a reentrant version of + * getpwnam(). So, we use the standard libc function. + */ + + return getpwnam(user); + +#endif /* def HAVE_GETPWNAM_R */ +} diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwuid.c b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c new file mode 100644 index 00000000..cd93ded4 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c @@ -0,0 +1,80 @@ +/* + * $Id: modutil_getpwuid.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * + * This function provides a thread safer version of getpwuid() for use + * with PAM modules that care about this sort of thing. + * + * XXX - or at least it should provide a thread-safe alternative. + */ + +#include "pammodutil.h" + +#include <pwd.h> +#include <stdlib.h> + +struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) +{ +#ifdef HAVE_GETPWNAM_R + + void *buffer=NULL; + size_t length = PWD_INITIAL_LENGTH; + + do { + int status; + void *new_buffer; + struct passwd *result = NULL; + + new_buffer = realloc(buffer, sizeof(struct passwd) + length); + if (new_buffer == NULL) { + + D(("out of memory")); + + /* no memory for the user - so delete the memory */ + if (buffer) { + free(buffer); + } + return NULL; + } + buffer = new_buffer; + + /* make the re-entrant call to get the pwd structure */ + status = getpwuid_r(uid, buffer, + sizeof(struct passwd) + (char *) buffer, + length, &result); + if (!status && result) { + status = pam_set_data(pamh, "_pammodutil_getpwuid", result, + _pammodutil_cleanup); + if (status == PAM_SUCCESS) { + D(("success")); + return result; + } + + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + + free(buffer); + return NULL; + + } + + length <<= 1; + + } while (length < PWD_ABSURD_PWD_LENGTH); + + D(("pwd structure took %u bytes or so of memory", + length+sizeof(struct passwd))); + + free(buffer); + return NULL; + +#else /* ie. ifndef HAVE_GETPWNAM_R */ + + /* + * Sorry, there does not appear to be a reentrant version of + * getpwnam(). So, we use the standard libc function. + */ + + return getpwuid(uid); + +#endif /* def HAVE_GETPWNAM_R */ +} diff --git a/Linux-PAM/modules/pammodutil/pammodutil.h b/Linux-PAM/modules/pammodutil/pammodutil.h new file mode 100644 index 00000000..78d7e517 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/pammodutil.h @@ -0,0 +1,22 @@ +#ifndef PAMMODUTIL_H +#define PAMMODUTIL_H + +/* + * $Id: pammodutil.h,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * + * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> + */ + +#include <security/_pam_aconf.h> +#include <security/_pam_macros.h> +#include <security/pam_modules.h> +#include <security/_pam_modutil.h> + +#define PWD_INITIAL_LENGTH 0x100 +#define PWD_ABSURD_PWD_LENGTH 0x1000 + +/* This is a simple cleanup, it just free()s the 'data' memory */ +extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, + int error_status); + +#endif /* PAMMODUTIL_H */ diff --git a/Linux-PAM/modules/register_static b/Linux-PAM/modules/register_static new file mode 100755 index 00000000..f3aebb60 --- /dev/null +++ b/Linux-PAM/modules/register_static @@ -0,0 +1,49 @@ +#!/bin/sh + +if [ `basename $PWD` != "modules" ]; then + echo "$0 must be run from the .../modules directory" + exit 1 +fi + +merge_line () +{ + if [ $# != 3 ]; then + echo "usage: merge_line token filename 'new line'" + fi + if [ -f $2 ]; then +# remove any existing entry... + grep -v "$1" $2 > tmp.$2 + rm -f $2 + mv {tmp.,}$2 + fi + cat << EOT >> $2 +$3 +EOT + +} + + +if [ $# -ne 2 ]; then + + cat << EOT 2>&1 +$0: this script takes TWO arguments: + the 'alphanumeric label' of the module and the location of + its object file from the .../modules/ directory +EOT + exit 1 + +else + echo " + *> registering static module: $1 ($2) <* +" + merge_line "$1" _static_module_list "\ +extern struct pam_module _$1_modstruct;" + + merge_line "$1" _static_module_entry " &_$1_modstruct," + if [ -n "$2" ]; then + merge_line "$2" _static_module_objects "../modules/$2" + fi + +fi + +exit 0 diff --git a/Linux-PAM/pgp.keys.asc b/Linux-PAM/pgp.keys.asc new file mode 100644 index 00000000..a516c379 --- /dev/null +++ b/Linux-PAM/pgp.keys.asc @@ -0,0 +1,103 @@ +Type Bits/KeyID Date User ID +pub 1024/2A398175 1996/11/17 Andrew G. Morgan <morgan@linux.kernel.org> + Andrew G. Morgan <morgan@transmeta.com> + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQCNAzKOhJ4AAAEEAJ9xYnZSD1kYanF+8GUBhHf/gx6hGd8ZNmS5qIC8Qb8rMcTI ++E16nV+FnNRlPRbShITYjq1TPvVK8gTliZf41N9LRQZw0rywRt1NQyhdfKgDWYxB +kSOwK67oDjkzzC56XS2rrGI6K3Rz/VtYElRyuQ6ZyaKTGcgU/TTwrUUqOYF1AAUR +tCpBbmRyZXcgRy4gTW9yZ2FuIDxtb3JnYW5AbGludXgua2VybmVsLm9yZz6JAJUD +BRA2iFK0NPCtRSo5gXUBAalqA/9s3Hx8BUESiC9PpL88KSVe3ENoO0ogAuMDK3vj +k2a17Twxi92Dc/NPXr8ewEKF/h1GiRetLBVPGaSVC+602+2cr5SHqzUzAeyF2Xa6 +VAxCskxkAssTxIW7nyAMWaOB5A/1xm3YChawVQx3XIvbIp+HXHDNr/60COtlGm7I +IcHftbQnQW5kcmV3IEcuIE1vcmdhbiA8bW9yZ2FuQHRyYW5zbWV0YS5jb20+iQCV +AwUQNohVmTTwrUUqOYF1AQEgWwP+K94N0OO+I2A7lnP5Jp7O+kfMJCFxPZOeozrq +O8uKsAs03ekS+kDJ3p2ec65BOzZyweHEu1HtOtdZbXsN3zynLKBwJrvvaHBQpAqv +BrjfNsl9a+NFmfa4fmdPWTzCaG2rmFlaQvZ6FP7QrHXB/1+VlH0gJ90FOgAd3Qyp +4hhW9g8= +=qQJI +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/4536A8DD 1996/01/28 Michael K. Johnson <johnsonm@redhat.com> + Michael K. Johnson <johnsonm@nigel.vnet.net> +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQCNAzEK0l0AAAEEAMWweYcS6ov1RISP6E7lb3vgQOrmhBy6S/8zkuHo92IkQWXm +V9AcMUY/eJPRJH6yI6o1ZKN4InT4uCkSIQOd2C8XyeIK5jFhpmP9DhoucacNL5H7 +oCV4wtFGhUDaDl9VeTtbWLSMESxJ4T/fL/IfkW95/Q2dF7zIDid5aW9FNqjdAAUR +tChNaWNoYWVsIEsuIEpvaG5zb24gPGpvaG5zb25tQHJlZGhhdC5jb20+iQCVAwUQ +MuqeiDTwrUUqOYF1AQEjywP/bCWLybbZSI8plyUSWD3yxwjsE+8BiOPGRu1AARUz +GbVZq9LqPDyjFtH9DqgXULyZtCAk8ebZonH/h/0EnZTi4tiZg3BHKXhIlWQnNz4D +QRdtUEmMNQzi9+3mU99CBGigsrDQnNrnI88ejo/0YY3gdt6752g5HAvY13h9A0ZP +MFWJAJUDBRAxgAouJ3lpb0U2qN0BActVA/9vgBOUheUpLPiIry/+2qqJv+e+LnHw +DgZqROpli9bhJ4wfb1sXPYkFzchR8BUeU0NY6HvAwxEilSNPE1yQoaJuy8POtTuu +aFO4wvuLp0v5LuatXaU8EsncwjrBsWqRB6Dqd+jyq24Pjx0YKNSRJxceiBE8SBDW +HESAhYTYCBLy77QsTWljaGFlbCBLLiBKb2huc29uIDxqb2huc29ubUBuaWdlbC52 +bmV0Lm5ldD6JAJUDBRAxGljWe01Ojay67k0BAf3qA/48N9OvgGk9nNR+Pg6aW3rK +2Dy8t2RQdFGd4b7gBtZeXUAklq9ppYZtS+cXFHoQ8d7K8XBjHh+rgF2oOSBQUrQf +eb8XkKSZQxB7DZVdi1gAsOzSwCrn4TWSSKc28P4Mjuj1Jr2f1FGST1+cGIl7JbhV +kLGjmvOIgs7lS8FE0Hhm/4kAlQMFEDEWclxEcVNogr/H7QEBN1QD/1iY+KYQyOTz +fgaBsx+Bt11kstmOlYhXx23yK2etG0p8XCD2r3aojGOTR/e3o2bLiJo4xe+iMhOM +dvdSzxSPGQ20wX3jGJaRrRiSClFTQbZSelGG0FcOGfM3mL5zeHaXzRcRciK3VDkD +IFzTQ3J5NJVBIVlAkxTMIxho758lR2SjiQCVAwUQMREqFnoDqzGe1QXFAQFdpAP/ +VPPoYO50seo1rLL28AA2PVKqo6BJwj0ZMsC14MDJEKryBbj/E4Ma25uSlzBjj+t9 +rbygoz0XWUQMLh8XPAEps3nE3n8FWROsdlucGzGiDGKVEygLPzCsjR7aGEspN1Y7 +4qOZPxbpGG7B5exOLur4ACY75m6oBh+PN+Q1liCIYXKJAJUDBRAxDpk1iGe2nxKR +G10BAeQjBACmx4DyJacQXxuckDaKMTXa8v2Q7lQpPDyHdn1oAUsx1mrbSL55v2AI +Q0riFWcFRTERpjAToCLgQjK1pKpmJcduiXURj6TPVKd88hYkuCIpn2hIaI7SCkd8 +HZlfFiuaxVN29UbbzHv3C+mseydpkPRrovqmOSuj2xAGFALo6Vl9U4kAlQMFEDEN +eD5EFXDNRmtCiQEBRmoEAJAuyY0F5hbweDOdeAhxLWeiTl9jGwQYDS3T5B5/9ZpC +bJ1yX7Pk2o7LvR9tg/Ji5sfMMvIpH48DNT4kyjmmChFXCUBccwd+33ugdTcYDwLR +Cdt7k9r2yXz1LEH+lVNKOEIhuIq8/sX61hvFR7+qSABthTLrvvynycD5n2pG3F7L +=aGjw +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/D4F4D901 1997/03/05 Cristian Gafton <gafton@sorosis.ro> + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQCNAzMdU6sAAAEEAKLF73rRJ3RUtl+y4bLUOVOV7ataJ46ZHxDZeGAVi+/suwT9 +Kq7QdaeFc4Xwaq8PVWv7pZ4/qTwHUkdbjBVeLt+KOlprvKuadyAh9aG/SqmKkEvA +hCS3yZDwNmeSLO7VIN5ko1nIwVD4kPJvS3xX6kn6jd4mvv/qGfGvxKXU9NkBAAUR +tCNDcmlzdGlhbiBHYWZ0b24gPGdhZnRvbkBzb3Jvc2lzLnJvPokAlQMFEDMeTlI0 +8K1FKjmBdQEBmgQD/02JxAU6+fiaBKwRIFDdsLYTy8mPgYaoul9RIX450W5D5nY/ +/696F6TfmFUzvnrvTbZUDyLxHB0mnh4SrdKRKo57i7RDrdx3Mqlt/xP4R6nHwFed +yTMvz3KB9tYuWfC1fJp69/VRIkMrw448zKkgqHUnAKxMIHvXnV3M9jd6lXSYiQCV +AwUQMx1Tq/GvxKXU9NkBAQE3/gP/RZMe59OkBWS4whc9c6eac6zwcC/hNc1vyiZ5 +2TEHJ10PgtNtHchD7j3xsDO17/DGEZB23OQiPAeLdqnBr+y2uiSlQfYdpVHBHX3A +uX3onc69LpEHmUAJAVOvfU1scnDtOH/KeVN3nwc6PWLxzLWzXfUbwLNK+LiPMNMV +1qygu+s= +=J4G2 +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/A5D75B79 1997/03/01 Andrey V. Savochkin <saw@msu.ru> + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQCNAzMYf1MAAAEEAK1S5jgmWnn8IS9mKoSpXu87f2soQhVZ3XdvsBCK2V7BojlU +0+JJrK+2gMH5tavyFsQ6cKch6I4xH54cS4P4tNE9M7OtfoXOxejtp9U9KZio8T0X +gM8qOS4fTQEfmdHSA5ETe5Vv+WPZ+/3SCo5kD1uIUUwppHDgJH+l396l11t5AAUR +tCBBbmRyZXkgVi4gU2F2b2Noa2luIDxzYXdAbXN1LnJ1PokAlQMFEDaIUh008K1F +KjmBdQEBFtkD/38mraXdr4aEYC6lxlG3cF+59XB6FjyBYhtwgNshpI2mB5XLr25p +f4jMFNUqnY/bGjXWKwbNguzJ0ukD8TgOg1ZXQZztRso1t1Y2M1KPbwlqj8ib1bZG +inQO/eqLrVwFH6F9CTiF0Fgy7faAIHN6BfE0o8earrcIwjT7sxRej3lziQCVAwUQ +M35653fqPT1smcpJAQHeqgQAlXMOru6Rz1TkslVrWD0n7dvBUHQxs0HS1pcWJnZJ +6kcYMLSA2RBi1fRabwzuOtzK60tOmfmnD7btcGBMMflOtfSulEg/xKNw2awEsNQK +ULEIBsvrpMr0UN4hWkxTggDXaykg7rQqgrbAsicoLuTtPDIbc+yhQcFEVGJiPO/I +tqiJAJUDBRAzfnUef89/VVw/1FkBAQ2lA/9q6FQM4RZzp75qxZ7jqAwUy9RFAKhp +L63YFJX3i1JsUjNoO51pjj5pEAxVVQsorqbdsmpC2aOUTf1AufEcs1kLojb3tc19 +MhXPyHTJs66QqWutdP/yOW+CLzmILAsbEgI6O+toVZ0rHVXjEtRgKUnYReHLrlYj +RKlBnkVc3NtPcIkAlQMFEDMYf1N/pd/epddbeQEBfKYD/3x/PkH2e+Cy7YXsfwxb +y/n+6eNIbfakSYjkwN5tDOeaKhdQKUJBKVwAzD2yrLmMDx6uW+FUOTucb6Anau6R +iKrAJq/a4DcpAeymo7cAthVU7en7HWwebQcL4wZGao1BJI+ulynki4sIqkfbGP83 +DK775eovl5X195ZkE/wNJvoi +=V5TY +-----END PGP PUBLIC KEY BLOCK----- diff --git a/Make.Rules.in b/Make.Rules.in deleted file mode 100644 index d7b87be2..00000000 --- a/Make.Rules.in +++ /dev/null @@ -1,110 +0,0 @@ -## -## $Id$ -## -## @configure_input@ -## - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ - -absolute_srcdir = @LOCALSRCDIR@ -absolute_objdir = @LOCALOBJDIR@ - -# major and minor numbers of this release -MAJOR_REL=@LIBPAM_VERSION_MAJOR@ -MINOR_REL=@LIBPAM_VERSION_MINOR@ - -# The following is the generic set of compiler options for compiling -# Linux-PAM. True, they are a little anal. Pay attention to the comments -# they generate. - -HEADER_DIRS=-I./include -I$(absolute_srcdir)/libpam/include \ - -I$(absolute_objdir) -I$(absolute_srcdir)/libpamc/include -WARNINGS=@WARNINGS@ -OS_CFLAGS=@OS_CFLAGS@ -PIC=@PIC@ - -# Mode to install shared libraries with -SHLIBMODE=@SHLIBMODE@ - -NEED_LINK_LIB_C=@PAM_NEEDS_LIBC@ -HAVE_LCKPWDF=@HAVE_LCKPWDF@ -HAVE_LIBCRACK=@HAVE_LIBCRACK@ -HAVE_LIBCRYPT=@HAVE_LIBCRYPT@ -HAVE_LIBUTIL=@HAVE_LIBUTIL@ -HAVE_NDBM_H=@HAVE_NDBM_H@ -HAVE_LIBNDBM=@HAVE_LIBNDBM@ -HAVE_LIBDB=@HAVE_LIBDB@ -HAVE_LIBFL=@HAVE_LIBFL@ -HAVE_LIBNSL=@HAVE_LIBNSL@ -HAVE_LIBPWDB=@HAVE_LIBPWDB@ - -ifeq (@HAVE_LIBFLEX@,yes) -LINK_LIBLEX=-lfl -else -ifeq (@HAVE_LIBLEX@,yes) -LINK_LIBLEX=-ll -endif -endif - -# documentation support -HAVE_SGML2TXT=@HAVE_SGML2TXT@ -HAVE_SGML2HTML=@HAVE_SGML2HTML@ -HAVE_PS2PDF=@HAVE_PS2PDF@ -PSER=@PSER@ -DOCDIR=@DOCDIR@ -MANDIR=@MANDIR@ - -# configuration settings -WITH_DEBUG=@WITH_DEBUG@ -WITH_MEMORY_DEBUG=@WITH_MEMORY_DEBUG@ -WITH_LIBDEBUG=@WITH_LIBDEBUG@ -WITH_PAMLOCKING=@WITH_PAMLOCKING@ -WITH_LCKPWDF=@WITH_LCKPWDF@ -STATIC_LIBPAM=@STATIC_LIBPAM@ -DYNAMIC_LIBPAM=@DYNAMIC_LIBPAM@ -STATIC=@STATIC@ -DYNAMIC=@DYNAMIC@ - -# Location of libraries when installed on the system -FAKEROOT=@FAKEROOT@ -SECUREDIR=@SECUREDIR@ -SCONFIGD=@SCONFIGDIR@ -SUPLEMENTED=@SUPLEMENTED@ -INCLUDED=@INCLUDEDIR@/security -CRACKLIB_DICTPATH=@CRACKLIB_DICTPATH@ - -# generic build setup -OS=@OS@ -CC=@CC@ -CFLAGS=$(WARNINGS) -D$(OS) $(OS_CFLAGS) $(HEADER_DIRS) @CONF_CFLAGS@ -LD=@LD@ -LD_D=@LD_D@ -LD_L=@LD_L@ -LDCONFIG=@LDCONFIG@ -DYNTYPE=@DYNTYPE@ -USESONAME=@USESONAME@ -NEEDSONAME=@NEEDSONAME@ -SOSWITCH=@SOSWITCH@ -LIBDL=@LIBDL@ -MKDIR=@MKDIR@ -INSTALL=@INSTALL@ -RANLIB=@RANLIB@ -STRIP=@STRIP@ -CC_STATIC=@CC_STATIC@ - -LINKLIBS = $(NEED_LINK_LIB_C) $(LIBDL) diff --git a/Makefile b/Makefile deleted file mode 100644 index 47c7bd39..00000000 --- a/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -## -## $Id$ -## - -## Note, ideally I would prefer it if this top level makefile did -## not get created by autoconf. As I find typing 'make' and relying -## on it to take care of all dependencies much more friendly than -## the multi-stage autoconf+make and also worry about updates to -## configure.in not getting propagated down the tree. (AGM) [I realise -## that this may not prove possible, but at least I tried.. Sigh.] - -DISTNAME=Linux-PAM - -ifeq ($(shell test \! -f Make.Rules || echo yes),yes) - include Make.Rules -endif - -THINGSTOMAKE = modules libpam libpamc libpam_misc doc examples - -all: $(THINGSTOMAKE) - -prep: - rm -f security - ln -sf . security - -clean: - if [ ! -f Make.Rules ]; then touch Make.Rules ; fi - for i in $(THINGSTOMAKE) ; do $(MAKE) -C $$i clean ; done - rm -f security *~ *.orig *.rej Make.Rules #*# - -distclean: clean - rm -f Make.Rules _pam_aconf.h - rm -f config.status config.cache config.log core - -maintainer-clean: distclean - @echo files should be ok for packaging now. - -# NB _pam_aconf.h.in changes will remake this too -Make.Rules: configure Make.Rules.in _pam_aconf.h.in - @echo XXX - not sure how to preserve past configure options.. - @echo XXX - so not attempting to. Feel free to run ./configure - @echo XXX - by hand, with the options you want. - ./configure - -_pam_aconf.h: Make.Rules - -configure: configure.in - @echo - @echo You do not appear to have an up-to-date ./configure file. - @echo Please run autoconf, and then ./configure [..options..] - @echo - @rm -f configure - @exit 1 - -$(THINGSTOMAKE): _pam_aconf.h prep - $(MAKE) -C $@ all - -install: _pam_aconf.h prep - $(MKDIR) $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 444 security/_pam_aconf.h $(FAKEROOT)$(INCLUDED) - for x in $(THINGSTOMAKE) ; do $(MAKE) -C $$x install ; done - -remove: - rm -f $(FAKEROOT)$(INCLUDED)/_pam_aconf.h - for x in $(THINGSTOMAKE) ; do $(MAKE) -C $$x remove ; done - -release: - @if [ ! -f Make.Rules ]; then echo $(MAKE) Make.Rules first ;exit 1 ;fi - @if [ ! -L ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ]; then \ - echo generating ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) link ; \ - ln -sf $(DISTNAME) ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL) ; \ - echo to ../$(DISTNAME) . ; fi - @diff ../$(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/Make.Rules Make.Rules - $(MAKE) distclean - cd .. ; tar zvfc $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL).tar.gz \ - --exclude CVS --exclude .cvsignore --exclude '.#*' \ - $(DISTNAME)-$(MAJOR_REL).$(MINOR_REL)/* - diff --git a/README b/README deleted file mode 100644 index a19e6f97..00000000 --- a/README +++ /dev/null @@ -1,28 +0,0 @@ -# -# $Id$ -# - -Hello! - -Thanks for downloading Linux-PAM. - -NOTES: - -How to use it is as follows: - - ./configure --help | less - ./configure <your-options> - make - -Note, if you are worried - don't even think about doing the next line -(most Linux distributions already support PAM out of the box, so if -something goes wrong with installing the code from this version your -box may stop working..) - - make install - -That said, please report problems to me. - -Andrew Morgan -<morgan@kernel.org> -<agmorgan@users.sourceforge.net> diff --git a/_pam_aconf.h.in b/_pam_aconf.h.in deleted file mode 100644 index 0569554d..00000000 --- a/_pam_aconf.h.in +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Id$ - * - * - */ - -#ifndef PAM_ACONF_H -#define PAM_ACONF_H - -/* lots of stuff gets written to /tmp/pam-debug.log */ -#undef DEBUG - -/* build libraries with different names (suffixed with 'd') */ -#undef WITH_LIBDEBUG - -/* provide a global locking facility within libpam */ -#undef PAM_LOCKING - -/* GNU systems as a class, all have the feature.h file */ -#undef HAVE_FEATURES_H -#ifdef HAVE_FEATURES_H -# define _SVID_SOURCE -# define _BSD_SOURCE -# define __USE_BSD -# define __USE_SVID -# define __USE_MISC -# define _GNU_SOURCE -# include <features.h> -#endif /* HAVE_FEATURES_H */ - -/* we have libcrack available */ -#undef HAVE_LIBCRACK - -/* we have libcrypt - its not part of libc (do we need both definitions?) */ -#undef HAVE_LIBCRYPT -#undef HAVE_CRYPT_H - -/* we have libndbm and/or libdb */ -#undef HAVE_DB_H -#undef HAVE_NDBM_H - -/* have libfl (Flex) */ -#undef HAVE_LIBFL - -/* have libnsl - instead of libc support */ -#undef HAVE_LIBNSL - -/* have libpwdb - don't expect this to be important for much longer */ -#undef HAVE_LIBPWDB - -/* have gethostname() declared */ -#undef HAVE_GETHOSTNAME - -#undef HAVE_GETTIMEOFDAY -#undef HAVE_MKDIR -#undef HAVE_SELECT -#undef HAVE_STRCSPN -#undef HAVE_STRDUP -#undef HAVE_STRERROR -#undef HAVE_STRSPN -#undef HAVE_STRSTR -#undef HAVE_STRTOL -#undef HAVE_UNAME - -/* Define if reentrant declarations of standard nss functions are available */ -#undef HAVE_GETPWNAM_R -#undef HAVE_GETGRNAM_R - -/* ugly hack to partially support old pam_strerror syntax */ -#undef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT - -/* read both confs - read /etc/pam.d and /etc/pam.conf in serial */ -#undef PAM_READ_BOTH_CONFS - -#undef HAVE_PATHS_H -#ifdef HAVE_PATHS_H -#include <paths.h> -#endif -/* location of the mail spool directory */ -#undef PAM_PATH_MAILDIR - -/* where should we include setfsuid's prototype from? If this is not - defined, we get it from unistd.h */ -#undef HAVE_SYS_FSUID_H - -/* track all memory allocations and liberations */ -#undef MEMORY_DEBUG -#ifdef MEMORY_DEBUG -/* - * this is basically a hack - we need to include a semiarbitrary - * number of headers to ensure that we don't get silly prototype/macro - * confusion. - */ -# include <string.h> -# include <stdlib.h> -# include <security/pam_malloc.h> -#endif /* MEMORY_DEBUG */ - -#endif /* PAM_ACONF_H */ diff --git a/bin/.cvsignore b/bin/.cvsignore deleted file mode 100644 index 2769a41e..00000000 --- a/bin/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -blank -xsh -check_user diff --git a/bin/README b/bin/README deleted file mode 100644 index c6b8fea3..00000000 --- a/bin/README +++ /dev/null @@ -1,30 +0,0 @@ -## -# $Id$ -## - -(now we are getting networked apps, be careful to try and test on a -securely isolated system!) - -N=2 <-- blank xsh - -Following a 'make install' (which should be done as root) in the -parent directory this directory will contain $N binaries. The source -for these programs is in ../examples. They are various short programs -to use and otherwise test-drive the Linux-PAM libraries/modules with. - -These programs grant no privileges, but they give an idea of how well -the modules are working. - -blank is new as of Linux-PAM-0.21. If you are writing/modifying an -application it might be a place to start... - -xsh is new as of Linux-PAM-0.31, it is identical to blank, but invokes -/bin/sh if the user is authenticated. - -[other apps are to be found in SimplePAMApps and many more on Red -Hat's server.. http://www.redhat.com/] - -Best wishes - -Andrew -(morgan@parc.power.net) diff --git a/conf/.cvsignore b/conf/.cvsignore deleted file mode 100644 index 93724758..00000000 --- a/conf/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -.ignore_age -.md5sum diff --git a/conf/Makefile b/conf/Makefile deleted file mode 100644 index d829a38c..00000000 --- a/conf/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# $Id$ -# -# - -dummy: - @echo "*** This is not a top level Makefile!" - -########################################################## - -all: - $(MAKE) -C pam_conv1 all - -install: $(FAKEROOT)$(CONFIGED)/pam.conf - $(MAKE) -C pam_conv1 install - -$(FAKEROOT)$(CONFIGED)/pam.conf: ./pam.conf - bash -f ./install_conf - -remove: - rm -f $(FAKEROOT)$(CONFIGED)/pam.conf - $(MAKE) -C pam_conv1 remove - -check: - bash -f ./md5itall - -lclean: - rm -f core *~ .ignore_age - -clean: lclean - $(MAKE) -C pam_conv1 clean - -extraclean: lclean - $(MAKE) -C pam_conv1 extraclean diff --git a/conf/install b/conf/install deleted file mode 100755 index 2eae3671..00000000 --- a/conf/install +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/sh -# -# [This file was lifted from an X distribution. There was no explicit -# copyright in the file, but the following text was associated with it. -# should anyone from the X Consortium wish to alter the following -# text. Please email <morgan@parc.power.net> Thanks. ] -# -# -------------------------- -# The X Consortium maintains and distributes the X Window System and -# related software and documentation in coordinated releases. A release -# consists of two distinct parts: -# -# 1) Specifications and Sample implementations of X Consortium -# standards, and -# -# 2) software and documentation contributed by the general X Consortium -# community. -# -# The timing and contents of a release are determined by the Consortium -# staff based on the needs and desires of the Members and the advice of -# the Advisory Board, tempered by the resource constraints of the -# Consortium. -# -# Members have access to all X Consortium produced software and -# documentation prior to release to the public. Each Member can receive -# pre-releases and public releases at no charge. In addition, Members -# have access to software and documentation while it is under -# development, and can periodically request snapshots of the development -# system at no charge. -# -# The X Consortium also maintains an electronic mail system for -# reporting problems with X Consortium produced software and -# documentation. Members have access to all bug reports, as well as all -# software patches as they are incrementally developed by the Consortium -# staff between releases. -# -# In general, all materials included in X Consortium releases are -# copyrighted and contain permission notices granting unrestricted use, -# sales and redistribution rights provided that the copyrights and the -# permission notices are left intact. All materials are provided "as -# is," without express or implied warranty. -# -------------------------- -# -# This accepts bsd-style install arguments and makes the appropriate calls -# to the System V install. -# - -flags="" -dst="" -src="" -dostrip="" -owner="" -mode="" - -while [ x$1 != x ]; do - case $1 in - -c) shift - continue;; - - -m) flags="$flags $1 $2 " - mode="$2" - shift - shift - continue;; - - -o) flags="$flags -u $2 " - owner="$2" - shift - shift - continue;; - - -g) flags="$flags $1 $2 " - shift - shift - continue;; - - -s) dostrip="strip" - shift - continue;; - - *) if [ x$src = x ] - then - src=$1 - else - dst=$1 - fi - shift - continue;; - esac -done - -case "$mode" in -"") - ;; -*) - case "$owner" in - "") - flags="$flags -u root" - ;; - esac - ;; -esac - -if [ x$src = x ] -then - echo "$0: no input file specified" - exit 1 -fi - -if [ x$dst = x ] -then - echo "$0: no destination specified" - exit 1 -fi - - -# set up some variable to be used later - -rmcmd="" -srcdir="." - -# if the destination isn't a directory we'll need to copy it first - -if [ ! -d $dst ] -then - dstbase=`basename $dst` - cp $src /tmp/$dstbase - rmcmd="rm -f /tmp/$dstbase" - src=$dstbase - srcdir=/tmp - dst="`echo $dst | sed 's,^\(.*\)/.*$,\1,'`" - if [ x$dst = x ] - then - dst="." - fi -fi - - -# If the src file has a directory, copy it to /tmp to make install happy - -srcbase=`basename $src` - -if [ "$src" != "$srcbase" -a "$src" != "./$srcbase" ] -then - cp $src /tmp/$srcbase - src=$srcbase - srcdir=/tmp - rmcmd="rm -f /tmp/$srcbase" -fi - -# do the actual install - -if [ -f /usr/sbin/install ] -then - installcmd=/usr/sbin/install -elif [ -f /etc/install ] -then - installcmd=/etc/install -else - installcmd=install -fi - -# This rm is commented out because some people want to be able to -# install through symbolic links. Uncomment it if it offends you. -rm -f $dst/$srcbase -(cd $srcdir ; $installcmd -f $dst $flags $src) - -if [ x$dostrip = xstrip ] -then - strip $dst/$srcbase -fi - -# and clean up - -$rmcmd - -exit - diff --git a/conf/install_conf b/conf/install_conf deleted file mode 100755 index 7a2acd98..00000000 --- a/conf/install_conf +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -CONFILE="$FAKEROOT"$CONFIGED/pam.conf -IGNORE_AGE=./.ignore_age -CONF=./pam.conf - -echo - -if [ -f "$IGNORE_AGE" ]; then - echo "you don't want to be bothered with the age of your $CONFILE file" - yes="n" -elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then - if [ -f "$CONFILE" ]; then - echo "\ -An older Linux-PAM configuration file already exists ($CONFILE)" - WRITE=overwrite - fi - echo -n "\ -Do you wish to copy the $CONF file in this distribution -to $CONFILE ? (y/n) [n] " - read yes -else - yes=n -fi - -if [ "$yes" = "y" ]; then - echo " copying $CONF to $CONFILE" - cp $CONF $CONFILE -else - touch "$IGNORE_AGE" - echo " Skipping $CONF installation" -fi - -echo - -exit 0 diff --git a/conf/md5itall b/conf/md5itall deleted file mode 100755 index b5fecc40..00000000 --- a/conf/md5itall +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# $Id$ -# -# Created by Andrew G. Morgan (morgan@parc.power.net) -# - -MD5SUM=md5sum -CHKFILE1=./.md5sum -CHKFILE2=./.md5sum-new - -which $MD5SUM > /dev/null -result=$? - -if [ -x "$MD5SUM" ] || [ $result -eq 0 ]; then - rm -f $CHKFILE2 - echo -n "computing md5 checksums." - for x in `cat ../.filelist` ; do - (cd ../.. ; $MD5SUM $x) >> $CHKFILE2 - echo -n "." - done - echo - if [ -f "$CHKFILE1" ]; then - echo "\ ----> Note, since the last \`make check', the following file(s) have changed: -===========================================================================" - diff $CHKFILE1 $CHKFILE2 - if [ $? -eq 0 ]; then - echo "\ ---------------------------- Nothing has changed ---------------------------" - fi - echo "\ -===========================================================================" - fi - rm -f "$CHKFILE1" - mv "$CHKFILE2" "$CHKFILE1" - chmod 400 "$CHKFILE1" -else - echo "\ -Please install \`$MD5SUM'. -[It is used to check the integrity of this distribution] ----> no check done." -fi diff --git a/conf/mkdirp b/conf/mkdirp deleted file mode 100755 index b0e04b05..00000000 --- a/conf/mkdirp +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh -# -# this is a wrapper for difficult mkdir programs... -# - -for d in $* -do - if [ ! -d $d ]; then - mkdir -p $d - if [ $? -ne 0 ]; then exit $? ; fi - fi -done - -exit 0 - -########################################################################## -# if your mkdir does not support the -p option delete the above lines and -# use what follows: --------------------- -#!/bin/sh - -#VERBOSE=yes -Cwd=`pwd` - -for d in $* -do - if [ "`echo $d|cut -c1`" != "/" ]; then - x=`pwd`/$d - else - x=$d - fi - x="`echo $x|sed -e 'yX/X X'`" - cd / - for s in $x - do - if [ -d $s ]; then - if [ -n "$VERBOSE" ]; then echo -n "[$s/]"; fi - cd $s - else - mkdir $s - if [ $? -ne 0 ]; then exit $? ; fi - if [ -n "$VERBOSE" ]; then echo -n "$s/"; fi - cd $s - fi - done - if [ -n "$VERBOSE" ]; then echo ; fi - cd $Cwd -done - -exit 0 diff --git a/conf/pam.conf b/conf/pam.conf deleted file mode 100644 index aa0e4130..00000000 --- a/conf/pam.conf +++ /dev/null @@ -1,126 +0,0 @@ -# ---------------------------------------------------------------------------# -# /etc/pam.conf # -# # -# Last modified by Andrew G. Morgan <morgan@kernel.org> # -# ---------------------------------------------------------------------------# -# $Id$ -# ---------------------------------------------------------------------------# -# serv. module ctrl module [path] ...[args..] # -# name type flag # -# ---------------------------------------------------------------------------# -# -# The PAM configuration file for the `chfn' service -# -chfn auth required pam_unix.so -chfn account required pam_unix.so -chfn password required pam_cracklib.so retry=3 -chfn password required pam_unix.so shadow md5 use_authtok -# -# The PAM configuration file for the `chsh' service -# -chsh auth required pam_unix.so -chsh account required pam_unix.so -chsh password required pam_cracklib.so retry=3 -chsh password required pam_unix.so shadow md5 use_authtok -# -# The PAM configuration file for the `ftp' service -# -ftp auth requisite pam_listfile.so \ - item=user sense=deny file=/etc/ftpusers onerr=succeed -ftp auth requisite pam_shells.so -ftp auth required pam_unix.so -ftp account required pam_unix.so -# -# The PAM configuration file for the `imap' service -# -imap auth required pam_unix.so -imap account required pam_unix.so -# -# The PAM configuration file for the `login' service -# -login auth requisite pam_securetty.so -login auth required pam_unix.so -login auth optional pam_group.so -login account requisite pam_time.so -login account required pam_unix.so -login password required pam_cracklib.so retry=3 -login password required pam_unix.so shadow md5 use_authtok -login session required pam_unix.so -# -# The PAM configuration file for the `netatalk' service -# -netatalk auth required pam_unix.so -netatalk account required pam_unix.so -# -# The PAM configuration file for the `other' service -# -other auth required pam_deny.so -other auth required pam_warn.so -other account required pam_deny.so -other password required pam_deny.so -other password required pam_warn.so -other session required pam_deny.so -# -# The PAM configuration file for the `passwd' service -# -passwd password requisite pam_cracklib.so retry=3 -passwd password required pam_unix.so shadow md5 use_authtok -# -# The PAM configuration file for the `rexec' service -# -rexec auth requisite pam_securetty.so -rexec auth requisite pam_nologin.so -rexec auth sufficient pam_rhosts_auth.so -rexec auth required pam_unix.so -rexec account required pam_unix.so -rexec session required pam_unix.so -rexec session required pam_limits.so -# -# The PAM configuration file for the `rlogin' service -# this application passes control to `login' if it fails -# -rlogin auth requisite pam_securetty.so -rlogin auth requisite pam_nologin.so -rlogin auth required pam_rhosts_auth.so -rlogin account required pam_unix.so -rlogin password required pam_cracklib.so retry=3 -rlogin password required pam_unix.so shadow md5 use_authtok -rlogin session required pam_unix.so -rlogin session required pam_limits.so -# -# The PAM configuration file for the `rsh' service -# -rsh auth requisite pam_securetty.so -rsh auth requisite pam_nologin.so -rsh auth sufficient pam_rhosts_auth.so -rsh auth required pam_unix.so -rsh account required pam_unix.so -rsh session required pam_unix.so -rsh session required pam_limits.so -# -# The PAM configuration file for the `samba' service -# -samba auth required pam_unix.so -samba account required pam_unix.so -# -# The PAM configuration file for the `su' service -# -su auth required pam_wheel.so -su auth sufficient pam_rootok.so -su auth required pam_unix.so -su account required pam_unix.so -su session required pam_unix.so -# -# The PAM configuration file for the `vlock' service -# -vlock auth required pam_unix.so -# -# The PAM configuration file for the `xdm' service -# -xdm auth required pam_unix.so -xdm account required pam_unix.so -# -# The PAM configuration file for the `xlock' service -# -xlock auth required pam_unix.so - diff --git a/conf/pam_conv1/.cvsignore b/conf/pam_conv1/.cvsignore deleted file mode 100644 index 200a991e..00000000 --- a/conf/pam_conv1/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -lex.yy.c -pam_conv.tab.c -pam_conv1 diff --git a/conf/pam_conv1/Makefile b/conf/pam_conv1/Makefile deleted file mode 100644 index 2fda767e..00000000 --- a/conf/pam_conv1/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# $Id$ -# - -include ../../Make.Rules - -# -ifeq ($(OS),solaris) - -clean: - @echo not available in Solaris - -all: - @echo not available in Solaris - -install: - @echo not available in Solaris - -else - -all: pam_conv1 - -pam_conv1: pam_conv.tab.c lex.yy.c - $(CC) -o pam_conv1 pam_conv.tab.c $(LINK_LIBLEX) - -pam_conv.tab.c: pam_conv.y lex.yy.c - bison pam_conv.y - -lex.yy.c: pam_conv.lex - flex pam_conv.lex - -lclean: - rm -f core pam_conv1 lex.yy.c pam_conv.tab.c *.o *~ - rm -rf ./pam.d pam_conv.output - -clean: lclean - -install: pam_conv1 - cp -f ./pam_conv1 ../../bin - -endif - -remove: - rm -f ../../bin/pam_conv1 - -extraclean: remove clean diff --git a/conf/pam_conv1/README b/conf/pam_conv1/README deleted file mode 100644 index 8d420ce4..00000000 --- a/conf/pam_conv1/README +++ /dev/null @@ -1,10 +0,0 @@ -$Id$ - -This directory contains a untility to convert pam.conf files to a pam.d/ -tree. The conversion program takes pam.conf from the standard input and -creates the pam.d/ directory in the current directory. - -The program will fail if ./pam.d/ already exists. - -Andrew Morgan, February 1997 - diff --git a/conf/pam_conv1/pam_conv.lex b/conf/pam_conv1/pam_conv.lex deleted file mode 100644 index a7df2b06..00000000 --- a/conf/pam_conv1/pam_conv.lex +++ /dev/null @@ -1,42 +0,0 @@ - -%{ -/* - * $Id$ - * - * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net> - * - * This file is covered by the Linux-PAM License (which should be - * distributed with this file.) - */ - - const static char lexid[]= - "$Id$\n" - "Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net>\n"; - - extern int current_line; -%} - -%% - -"#"[^\n]* ; /* skip comments (sorry) */ - -"\\\n" { - ++current_line; -} - -([^\n\t ]|[\\][^\n])+ { - return TOK; -} - -[ \t]+ ; /* Ignore */ - -<<EOF>> { - return EOFILE; -} - -[\n] { - ++current_line; - return NL; -} - -%% diff --git a/conf/pam_conv1/pam_conv.y b/conf/pam_conv1/pam_conv.y deleted file mode 100644 index f42b634e..00000000 --- a/conf/pam_conv1/pam_conv.y +++ /dev/null @@ -1,204 +0,0 @@ -%{ - -/* - * $Id$ - * - * Copyright (c) Andrew G. Morgan 1997 <morgan@parc.power.net> - * - * This file is covered by the Linux-PAM License (which should be - * distributed with this file.) - */ - - const static char bisonid[]= - "$Id$\n" - "Copyright (c) Andrew G. Morgan 1997-8 <morgan@linux.kernel.org>\n"; - -#include <string.h> -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> - - int current_line=1; - extern char *yytext; - -/* XXX - later we'll change this to be the specific conf file(s) */ -#define newpamf stderr - -#define PAM_D "./pam.d" -#define PAM_D_MODE 0755 -#define PAM_D_MAGIC_HEADER \ - "#%PAM-1.0\n" \ - "#[For version 1.0 syntax, the above header is optional]\n" - -#define PAM_D_FILE_FMT PAM_D "/%s" - - const char *old_to_new_ctrl_flag(const char *old); - void yyerror(const char *format, ...); -%} - -%union { - int def; - char *string; -} - -%token NL EOFILE TOK - -%type <string> tok path tokenls - -%start complete - -%% - -complete -: -| complete NL -| complete line -| complete EOFILE { - return 0; -} -; - -line -: tok tok tok path tokenls NL { - char *filename; - FILE *conf; - int i; - - /* make sure we have lower case */ - for (i=0; $1[i]; ++i) { - $1[i] = tolower($1[i]); - } - - /* $1 = service-name */ - yyerror("Appending to " PAM_D "/%s", $1); - - filename = malloc(strlen($1) + sizeof(PAM_D) + 6); - sprintf(filename, PAM_D_FILE_FMT, $1); - conf = fopen(filename, "r"); - if (conf == NULL) { - /* new file */ - conf = fopen(filename, "w"); - if (conf != NULL) { - fprintf(conf, PAM_D_MAGIC_HEADER); - fprintf(conf, - "#\n" - "# The PAM configuration file for the `%s' service\n" - "#\n", $1); - } - } else { - fclose(conf); - conf = fopen(filename, "a"); - } - if (conf == NULL) { - yyerror("trouble opening %s - aborting", filename); - exit(1); - } - free(filename); - - /* $2 = module-type */ - fprintf(conf, "%-10s", $2); - free($2); - - /* $3 = required etc. */ - { - const char *trans; - - trans = old_to_new_ctrl_flag($3); - free($3); - fprintf(conf, " %-10s", trans); - } - - /* $4 = module-path */ - fprintf(conf, " %s", $4); - free($4); - - /* $5 = arguments */ - if ($5 != NULL) { - fprintf(conf, " \\\n\t\t%s", $5); - free($5); - } - - /* end line */ - fprintf(conf, "\n"); - - fclose(conf); -} -| error NL { - yyerror("malformed line"); -} -; - -tokenls -: { - $$=NULL; -} -| tokenls tok { - int len; - - if ($1) { - len = strlen($1) + strlen($2) + 2; - $$ = malloc(len); - sprintf($$,"%s %s",$1,$2); - free($1); - free($2); - } else { - $$ = $2; - } -} -; - -path -: TOK { - /* XXX - this could be used to check if file present */ - $$ = strdup(yytext); -} - -tok -: TOK { - $$ = strdup(yytext); -} - -%% - -#include "lex.yy.c" - -const char *old_to_new_ctrl_flag(const char *old) -{ - static const char *clist[] = { - "requisite", - "required", - "sufficient", - "optional", - NULL, - }; - int i; - - for (i=0; clist[i]; ++i) { - if (strcasecmp(clist[i], old) == 0) { - break; - } - } - - return clist[i]; -} - -void yyerror(const char *format, ...) -{ - va_list args; - - fprintf(stderr, "line %d: ", current_line); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\n"); -} - -int main(int argc, char *argv[]) -{ - if (mkdir(PAM_D, PAM_D_MODE) != 0) { - yyerror(PAM_D " already exists.. aborting"); - exit(1); - } - yyparse(); - exit(0); -} diff --git a/configure b/configure deleted file mode 100755 index 270184c7..00000000 --- a/configure +++ /dev/null @@ -1,3887 +0,0 @@ -#! /bin/sh - -# Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.13 -# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. - -# Defaults: -ac_help= -ac_default_prefix=/usr/local -# Any additions from configure.in: -ac_default_prefix= -ac_help="$ac_help - --enable-debug specify you are building with debugging on" -ac_help="$ac_help - --enable-memory-debug specify you want every malloc etc. call tracked" -ac_help="$ac_help - --enable-libdebug specify you are building debugging libraries" -ac_help="$ac_help - --enable-fakeroot=<path to packaging directory>" -ac_help="$ac_help - --enable-securedir=<path to location of PAMs> [default \$libdir/security]" -ac_help="$ac_help - --enable-sconfigdir=<path to module conf files> [default \$sysconfdir/security]" -ac_help="$ac_help - --enable-suplementedir=<path to module helper binaries> [default \$sbindir]" -ac_help="$ac_help - --enable-includedir=<path to include location> - where to put <security>" -ac_help="$ac_help - --enable-docdir=<path to store documentation in - /usr/share/doc/pam>" -ac_help="$ac_help - --enable-mandir=<path to store manuals in - /usr/share/man>" -ac_help="$ac_help - --enable-pamlocking configure libpam to observe a global authentication lock" -ac_help="$ac_help - --enable-uglyhack configure libpam to try to honor old pam_strerror syntax" -ac_help="$ac_help - --enable-read-both-confs read both /etc/pam.d and /etc/pam.conf files" -ac_help="$ac_help - --enable-static-libpam build a libpam.a library" -ac_help="$ac_help - --disable-dynamic-libpam do not build a shared libpam library" -ac_help="$ac_help - --enable-static-modules do not make the modules dynamically loadable" -ac_help="$ac_help - --disable-lckpwdf do not use the lckpwdf function" -ac_help="$ac_help - --with-mailspool path to mail spool directory - [default _PATH_MAILDIR if defined in paths.h, otherwise /var/spool/mail]" - -# Initialize some variables set by options. -# The variables have the same names as the options, with -# dashes changed to underlines. -build=NONE -cache_file=./config.cache -exec_prefix=NONE -host=NONE -no_create= -nonopt=NONE -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -target=NONE -verbose= -x_includes=NONE -x_libraries=NONE -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datadir='${prefix}/share' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -libdir='${exec_prefix}/lib' -includedir='${prefix}/include' -oldincludedir='/usr/include' -infodir='${prefix}/info' -mandir='${prefix}/man' - -# Initialize some other variables. -subdirs= -MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} -# Maximum number of lines to put in a shell here document. -ac_max_here_lines=12 - -ac_prev= -for ac_option -do - - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval "$ac_prev=\$ac_option" - ac_prev= - continue - fi - - case "$ac_option" in - -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) ac_optarg= ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case "$ac_option" in - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir="$ac_optarg" ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build="$ac_optarg" ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file="$ac_optarg" ;; - - -datadir | --datadir | --datadi | --datad | --data | --dat | --da) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ - | --da=*) - datadir="$ac_optarg" ;; - - -disable-* | --disable-*) - ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - eval "enable_${ac_feature}=no" ;; - - -enable-* | --enable-*) - ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "enable_${ac_feature}='$ac_optarg'" ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix="$ac_optarg" ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he) - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat << EOF -Usage: configure [options] [host] -Options: [defaults in brackets after descriptions] -Configuration: - --cache-file=FILE cache test results in FILE - --help print this message - --no-create do not create output files - --quiet, --silent do not print \`checking...' messages - --version print the version of autoconf that created configure -Directory and file names: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [same as prefix] - --bindir=DIR user executables in DIR [EPREFIX/bin] - --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] - --libexecdir=DIR program executables in DIR [EPREFIX/libexec] - --datadir=DIR read-only architecture-independent data in DIR - [PREFIX/share] - --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data in DIR - [PREFIX/com] - --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] - --libdir=DIR object code libraries in DIR [EPREFIX/lib] - --includedir=DIR C header files in DIR [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] - --infodir=DIR info documentation in DIR [PREFIX/info] - --mandir=DIR man documentation in DIR [PREFIX/man] - --srcdir=DIR find the sources in DIR [configure dir or ..] - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM - run sed PROGRAM on installed program names -EOF - cat << EOF -Host type: - --build=BUILD configure for building on BUILD [BUILD=HOST] - --host=HOST configure for HOST [guessed] - --target=TARGET configure for TARGET [TARGET=HOST] -Features and packages: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR -EOF - if test -n "$ac_help"; then - echo "--enable and --with options recognized:$ac_help" - fi - exit 0 ;; - - -host | --host | --hos | --ho) - ac_prev=host ;; - -host=* | --host=* | --hos=* | --ho=*) - host="$ac_optarg" ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir="$ac_optarg" ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir="$ac_optarg" ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir="$ac_optarg" ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir="$ac_optarg" ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst \ - | --locals | --local | --loca | --loc | --lo) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* \ - | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) - localstatedir="$ac_optarg" ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir="$ac_optarg" ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir="$ac_optarg" ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix="$ac_optarg" ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix="$ac_optarg" ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix="$ac_optarg" ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name="$ac_optarg" ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir="$ac_optarg" ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir="$ac_optarg" ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site="$ac_optarg" ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir="$ac_optarg" ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir="$ac_optarg" ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target="$ac_optarg" ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.13" - exit 0 ;; - - -with-* | --with-*) - ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "with_${ac_package}='$ac_optarg'" ;; - - -without-* | --without-*) - ac_package=`echo $ac_option|sed -e 's/-*without-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - eval "with_${ac_package}=no" ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes="$ac_optarg" ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries="$ac_optarg" ;; - - -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } - ;; - - *) - if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then - echo "configure: warning: $ac_option: invalid host type" 1>&2 - fi - if test "x$nonopt" != xNONE; then - { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } - fi - nonopt="$ac_option" - ;; - - esac -done - -if test -n "$ac_prev"; then - { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } -fi - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -# File descriptor usage: -# 0 standard input -# 1 file creation -# 2 errors and warnings -# 3 some systems may open it to /dev/tty -# 4 used on the Kubota Titan -# 6 checking for... messages and results -# 5 compiler messages saved in config.log -if test "$silent" = yes; then - exec 6>/dev/null -else - exec 6>&1 -fi -exec 5>./config.log - -echo "\ -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. -" 1>&5 - -# Strip out --no-create and --no-recursion so they do not pile up. -# Also quote any args containing shell metacharacters. -ac_configure_args= -for ac_arg -do - case "$ac_arg" in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) - ac_configure_args="$ac_configure_args '$ac_arg'" ;; - *) ac_configure_args="$ac_configure_args $ac_arg" ;; - esac -done - -# NLS nuisances. -# Only set these to C if already set. These must not be set unconditionally -# because not all systems understand e.g. LANG=C (notably SCO). -# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! -# Non-C LC_CTYPE values break the ctype check. -if test "${LANG+set}" = set; then LANG=C; export LANG; fi -if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi -if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi -if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -rf conftest* confdefs.h -# AIX cpp loses on an empty file, so make sure it contains at least a newline. -echo > confdefs.h - -# A filename unique to this package, relative to the directory that -# configure is in, which we can look for to find out if srcdir is correct. -ac_unique_file=conf/pam_conv1/pam_conv.y - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then its parent. - ac_prog=$0 - ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` - test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. - srcdir=$ac_confdir - if test ! -r $srcdir/$ac_unique_file; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r $srcdir/$ac_unique_file; then - if test "$ac_srcdir_defaulted" = yes; then - { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } - else - { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } - fi -fi -srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` - -# Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi -fi -for ac_site_file in $CONFIG_SITE; do - if test -r "$ac_site_file"; then - echo "loading site script $ac_site_file" - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - echo "loading cache $cache_file" - . $cache_file -else - echo "creating cache $cache_file" - > $cache_file -fi - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -ac_exeext= -ac_objext=o -if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then - # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. - if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then - ac_n= ac_c=' -' ac_t=' ' - else - ac_n=-n ac_c= ac_t= - fi -else - ac_n= ac_c='\c' ac_t= -fi - - - - - - -LIBPAM_VERSION_MAJOR=0 -LIBPAM_VERSION_MINOR=76 - - - -cat >> confdefs.h <<\EOF -#define LIBPAM_VERSION_MAJOR 1 -EOF - -cat >> confdefs.h <<\EOF -#define LIBPAM_VERSION_MINOR 1 -EOF - - - - - -LOCALSRCDIR=`/bin/pwd` ; -LOCALOBJDIR=`/bin/pwd` ; -OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` - - - -CONF_CFLAGS= ; -MKDIR="mkdir -p" ; - -SHLIBMODE=755 ; - -USESONAME=yes ; -SOSWITCH=-soname ; -NEEDSONAME=no ; -LDCONFIG=/sbin/ldconfig ; - -if test "$OS" = "aix"; then - INSTALL=/usr/ucb/install -c -else - INSTALL=/usr/bin/install -fi - - -# Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:610: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="gcc" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:640: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_prog_rejected=no - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - break - fi - done - IFS="$ac_save_ifs" -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# -gt 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - set dummy "$ac_dir/$ac_word" "$@" - shift - ac_cv_prog_CC="$@" - fi -fi -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - if test -z "$CC"; then - case "`uname -s`" in - *win32* | *WIN32*) - # Extract the first word of "cl", so it can be a program name with args. -set dummy cl; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:691: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="cl" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - ;; - esac - fi - test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } -fi - -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:723: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -cat > conftest.$ac_ext << EOF - -#line 734 "configure" -#include "confdefs.h" - -main(){return(0);} -EOF -if { (eval echo configure:739: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - ac_cv_prog_cc_works=yes - # If we can't run a trivial program, we are probably using a cross compiler. - if (./conftest; exit) 2>/dev/null; then - ac_cv_prog_cc_cross=no - else - ac_cv_prog_cc_cross=yes - fi -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_prog_cc_works=no -fi -rm -fr conftest* -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cc_cross - -echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 -if test $ac_cv_prog_cc_works = no; then - { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } -fi -echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:765: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 -echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 -cross_compiling=$ac_cv_prog_cc_cross - -echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:770: checking whether we are using GNU C" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.c <<EOF -#ifdef __GNUC__ - yes; -#endif -EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:779: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then - ac_cv_prog_gcc=yes -else - ac_cv_prog_gcc=no -fi -fi - -echo "$ac_t""$ac_cv_prog_gcc" 1>&6 - -if test $ac_cv_prog_gcc = yes; then - GCC=yes -else - GCC= -fi - -ac_test_CFLAGS="${CFLAGS+set}" -ac_save_CFLAGS="$CFLAGS" -CFLAGS= -echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:798: checking whether ${CC-cc} accepts -g" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - echo 'void f(){}' > conftest.c -if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then - ac_cv_prog_cc_g=yes -else - ac_cv_prog_cc_g=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 -if test "$ac_test_CFLAGS" = set; then - CFLAGS="$ac_save_CFLAGS" -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi - -for ac_prog in 'bison -y' byacc -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:834: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$YACC"; then - ac_cv_prog_YACC="$YACC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_YACC="$ac_prog" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -YACC="$ac_cv_prog_YACC" -if test -n "$YACC"; then - echo "$ac_t""$YACC" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$YACC" && break -done -test -n "$YACC" || YACC="yacc" - -# Extract the first word of "flex", so it can be a program name with args. -set dummy flex; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:867: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$LEX"; then - ac_cv_prog_LEX="$LEX" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_LEX="flex" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" -fi -fi -LEX="$ac_cv_prog_LEX" -if test -n "$LEX"; then - echo "$ac_t""$LEX" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -if test -z "$LEXLIB" -then - case "$LEX" in - flex*) ac_lib=fl ;; - *) ac_lib=l ;; - esac - echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 -echo "configure:901: checking for yywrap in -l$ac_lib" >&5 -ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-l$ac_lib $LIBS" -cat > conftest.$ac_ext <<EOF -#line 909 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char yywrap(); - -int main() { -yywrap() -; return 0; } -EOF -if { (eval echo configure:920: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LEXLIB="-l$ac_lib" -else - echo "$ac_t""no" 1>&6 -fi - -fi - -echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:943: checking whether ln -s works" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - rm -f conftestdata -if ln -s X conftestdata 2>/dev/null -then - rm -f conftestdata - ac_cv_prog_LN_S="ln -s" -else - ac_cv_prog_LN_S=ln -fi -fi -LN_S="$ac_cv_prog_LN_S" -if test "$ac_cv_prog_LN_S" = "ln -s"; then - echo "$ac_t""yes" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:964: checking whether ${MAKE-make} sets \${MAKE}" >&5 -set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftestmake <<\EOF -all: - @echo 'ac_maketemp="${MAKE}"' -EOF -# GNU make sometimes prints "make[1]: Entering...", which would confuse us. -eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` -if test -n "$ac_maketemp"; then - eval ac_cv_prog_make_${ac_make}_set=yes -else - eval ac_cv_prog_make_${ac_make}_set=no -fi -rm -f conftestmake -fi -if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then - echo "$ac_t""yes" 1>&6 - SET_MAKE= -else - echo "$ac_t""no" 1>&6 - SET_MAKE="MAKE=${MAKE-make}" -fi - - - -# Check whether --enable-debug or --disable-debug was given. -if test "${enable_debug+set}" = set; then - enableval="$enable_debug" - WITH_DEBUG=yes ; cat >> confdefs.h <<\EOF -#define DEBUG 1 -EOF - -else - WITH_DEBUG=no -fi - - - -# Check whether --enable-memory-debug or --disable-memory-debug was given. -if test "${enable_memory_debug+set}" = set; then - enableval="$enable_memory_debug" - WITH_MEMORY_DEBUG=yes ; cat >> confdefs.h <<\EOF -#define MEMORY_DEBUG 1 -EOF - -else - WITH_MEMORY_DEBUG=no -fi - - - -# Check whether --enable-libdebug or --disable-libdebug was given. -if test "${enable_libdebug+set}" = set; then - enableval="$enable_libdebug" - WITH_LIBDEBUG=yes ; cat >> confdefs.h <<\EOF -#define WITH_LIBDEBUG 1 -EOF - -else - WITH_LIBDEBUG=no -fi - - - -# Check whether --enable-fakeroot or --disable-fakeroot was given. -if test "${enable_fakeroot+set}" = set; then - enableval="$enable_fakeroot" - FAKEROOT=$enableval -fi - - - -# Check whether --enable-securedir or --disable-securedir was given. -if test "${enable_securedir+set}" = set; then - enableval="$enable_securedir" - SECUREDIR=$enableval -else - SECUREDIR=$libdir/security -fi - - - -# Check whether --enable-sconfigdir or --disable-sconfigdir was given. -if test "${enable_sconfigdir+set}" = set; then - enableval="$enable_sconfigdir" - SCONFIGDIR=$enableval -else - SCONFIGDIR=$sysconfdir/security -fi - - - -# Check whether --enable-suplementedir or --disable-suplementedir was given. -if test "${enable_suplementedir+set}" = set; then - enableval="$enable_suplementedir" - SUPLEMENTED=$enableval -else - SUPLEMENTED=$sbindir -fi - - - -# Check whether --enable-includedir or --disable-includedir was given. -if test "${enable_includedir+set}" = set; then - enableval="$enable_includedir" - INCLUDEDIR=$enableval -else - INCLUDEDIR=/usr/include -fi - - - -# Check whether --enable-docdir or --disable-docdir was given. -if test "${enable_docdir+set}" = set; then - enableval="$enable_docdir" - DOCDIR=$enableval -else - DOCDIR=/usr/share/doc/pam -fi - - - -# Check whether --enable-mandir or --disable-mandir was given. -if test "${enable_mandir+set}" = set; then - enableval="$enable_mandir" - MANDIR=$enableval -else - MANDIR=/usr/share/man -fi - - - -# Check whether --enable-pamlocking or --disable-pamlocking was given. -if test "${enable_pamlocking+set}" = set; then - enableval="$enable_pamlocking" - WITH_PAMLOCKING=yes ; cat >> confdefs.h <<\EOF -#define PAM_LOCKING 1 -EOF - -else - WITH_PAMLOCKING=no -fi - - - -# Check whether --enable-uglyhack or --disable-uglyhack was given. -if test "${enable_uglyhack+set}" = set; then - enableval="$enable_uglyhack" - cat >> confdefs.h <<\EOF -#define UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT 1 -EOF - -fi - - -# Check whether --enable-read-both-confs or --disable-read-both-confs was given. -if test "${enable_read_both_confs+set}" = set; then - enableval="$enable_read_both_confs" - cat >> confdefs.h <<\EOF -#define PAM_READ_BOTH_CONFS 1 -EOF - -fi - - - -# Check whether --enable-static-libpam or --disable-static-libpam was given. -if test "${enable_static_libpam+set}" = set; then - enableval="$enable_static_libpam" - STATIC_LIBPAM=yes -else - STATIC_LIBPAM=no -fi - - - -# Check whether --enable-dynamic-libpam or --disable-dynamic-libpam was given. -if test "${enable_dynamic_libpam+set}" = set; then - enableval="$enable_dynamic_libpam" - DYNAMIC_LIBPAM=no -else - DYNAMIC_LIBPAM=yes -fi - - - -DYNAMIC=-DPAM_DYNAMIC - - -# Check whether --enable-static-modules or --disable-static-modules was given. -if test "${enable_static_modules+set}" = set; then - enableval="$enable_static_modules" - STATIC=-DPAM_STATIC -fi - - - -# Check whether --enable-lckpwdf or --disable-lckpwdf was given. -if test "${enable_lckpwdf+set}" = set; then - enableval="$enable_lckpwdf" - WITH_LCKPWDF=no -else - WITH_LCKPWDF=yes -fi - - - -echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1175: checking how to run the C preprocessor" >&5 -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then -if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - # This must be in double quotes, not single quotes, because CPP may get - # substituted into the Makefile and "${CC-cc}" will confuse make. - CPP="${CC-cc} -E" - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. - cat > conftest.$ac_ext <<EOF -#line 1190 "configure" -#include "confdefs.h" -#include <assert.h> -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1196: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP="${CC-cc} -E -traditional-cpp" - cat > conftest.$ac_ext <<EOF -#line 1207 "configure" -#include "confdefs.h" -#include <assert.h> -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1213: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP="${CC-cc} -nologo -E" - cat > conftest.$ac_ext <<EOF -#line 1224 "configure" -#include "confdefs.h" -#include <assert.h> -Syntax Error -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1230: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - CPP=/lib/cpp -fi -rm -f conftest* -fi -rm -f conftest* -fi -rm -f conftest* - ac_cv_prog_CPP="$CPP" -fi - CPP="$ac_cv_prog_CPP" -else - ac_cv_prog_CPP="$CPP" -fi -echo "$ac_t""$CPP" 1>&6 - -for ac_hdr in paths.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1258: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 1263 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1268: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - -# Check whether --with-mailspool or --without-mailspool was given. -if test "${with_mailspool+set}" = set; then - withval="$with_mailspool" - with_mailspool=${withval} -fi - -if test x$with_mailspool != x ; then - pam_mail_spool="\"$with_mailspool\"" -else - if test "$cross_compiling" = yes; then - pam_mail_spool="\"/var/spool/mail\"" -else - cat > conftest.$ac_ext <<EOF -#line 1307 "configure" -#include "confdefs.h" - -#include <paths.h> -int main() { -#ifdef _PATH_MAILDIR -exit(0); -#else -exit(1); -#endif -} -EOF -if { (eval echo configure:1319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then - pam_mail_spool="_PATH_MAILDIR" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - pam_mail_spool="\"/var/spool/mail\"" -fi -rm -fr conftest* -fi - -fi -cat >> confdefs.h <<EOF -#define PAM_PATH_MAILDIR $pam_mail_spool -EOF - - -echo $ac_n "checking for __libc_sched_setscheduler in -lc""... $ac_c" 1>&6 -echo "configure:1338: checking for __libc_sched_setscheduler in -lc" >&5 -ac_lib_var=`echo c'_'__libc_sched_setscheduler | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lc $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1346 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char __libc_sched_setscheduler(); - -int main() { -__libc_sched_setscheduler() -; return 0; } -EOF -if { (eval echo configure:1357: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - PAM_NEEDS_LIBC= -else - echo "$ac_t""no" 1>&6 -PAM_NEEDS_LIBC=-lc -fi - - - -echo $ac_n "checking for lckpwdf in -lc""... $ac_c" 1>&6 -echo "configure:1381: checking for lckpwdf in -lc" >&5 -ac_lib_var=`echo c'_'lckpwdf | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lc $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1389 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char lckpwdf(); - -int main() { -lckpwdf() -; return 0; } -EOF -if { (eval echo configure:1400: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LCKPWDF=yes -else - echo "$ac_t""no" 1>&6 -HAVE_LCKPWDF=no -fi - - - -echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:1424: checking for dlopen in -ldl" >&5 -ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldl $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1432 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dlopen(); - -int main() { -dlopen() -; return 0; } -EOF -if { (eval echo configure:1443: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LIBDL=-ldl -else - echo "$ac_t""no" 1>&6 -fi - - - -echo $ac_n "checking for FascistCheck in -lcrack""... $ac_c" 1>&6 -echo "configure:1466: checking for FascistCheck in -lcrack" >&5 -ac_lib_var=`echo crack'_'FascistCheck | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lcrack $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1474 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char FascistCheck(); - -int main() { -FascistCheck() -; return 0; } -EOF -if { (eval echo configure:1485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBCRACK=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBCRACK 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBCRACK=no -fi - - - -echo $ac_n "checking for fcrypt in -lcrypt""... $ac_c" 1>&6 -echo "configure:1512: checking for fcrypt in -lcrypt" >&5 -ac_lib_var=`echo crypt'_'fcrypt | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lcrypt $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1520 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char fcrypt(); - -int main() { -fcrypt() -; return 0; } -EOF -if { (eval echo configure:1531: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBCRYPT=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBCRYPT 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBCRYPT=no -fi - - -echo $ac_n "checking for logwtmp in -lutil""... $ac_c" 1>&6 -echo "configure:1557: checking for logwtmp in -lutil" >&5 -ac_lib_var=`echo util'_'logwtmp | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lutil $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1565 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char logwtmp(); - -int main() { -logwtmp() -; return 0; } -EOF -if { (eval echo configure:1576: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBUTIL=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBUTIL 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBUTIL=no -fi - - -echo $ac_n "checking for dbm_store in -lndbm""... $ac_c" 1>&6 -echo "configure:1602: checking for dbm_store in -lndbm" >&5 -ac_lib_var=`echo ndbm'_'dbm_store | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lndbm $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1610 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dbm_store(); - -int main() { -dbm_store() -; return 0; } -EOF -if { (eval echo configure:1621: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBNDBM=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBNDBM 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBNDBM=no -fi - - -echo $ac_n "checking for dbm_store in -ldb""... $ac_c" 1>&6 -echo "configure:1647: checking for dbm_store in -ldb" >&5 -ac_lib_var=`echo db'_'dbm_store | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldb $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1655 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dbm_store(); - -int main() { -dbm_store() -; return 0; } -EOF -if { (eval echo configure:1666: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBDB=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBDB 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBDB=no -fi - -if test x$HAVE_LIBDB != xyes ; then - echo $ac_n "checking for db_create in -ldb""... $ac_c" 1>&6 -echo "configure:1692: checking for db_create in -ldb" >&5 -ac_lib_var=`echo db'_'db_create | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldb $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1700 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char db_create(); - -int main() { -db_create() -; return 0; } -EOF -if { (eval echo configure:1711: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBDB=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBDB 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBDB=no -fi - -fi - -echo $ac_n "checking for yylex in -lfl""... $ac_c" 1>&6 -echo "configure:1738: checking for yylex in -lfl" >&5 -ac_lib_var=`echo fl'_'yylex | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lfl HAVE_LIBFL=no $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1746 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char yylex(); - -int main() { -yylex() -; return 0; } -EOF -if { (eval echo configure:1757: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - yyterminate -else - echo "$ac_t""no" 1>&6 -HAVE_LIBFL=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBFL 1 -EOF - -fi - - -echo $ac_n "checking for yp_maplist in -lnsl""... $ac_c" 1>&6 -echo "configure:1783: checking for yp_maplist in -lnsl" >&5 -ac_lib_var=`echo nsl'_'yp_maplist | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lnsl $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1791 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char yp_maplist(); - -int main() { -yp_maplist() -; return 0; } -EOF -if { (eval echo configure:1802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBNSL=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBNSL 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBNSL=no -fi - - -echo $ac_n "checking for pwdb_db_name in -lpwdb""... $ac_c" 1>&6 -echo "configure:1828: checking for pwdb_db_name in -lpwdb" >&5 -ac_lib_var=`echo pwdb'_'pwdb_db_name | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lpwdb $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1836 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char pwdb_db_name(); - -int main() { -pwdb_db_name() -; return 0; } -EOF -if { (eval echo configure:1847: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBPWDB=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBPWDB 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBPWDB=no -fi - - -echo $ac_n "checking for yywrap in -lfl""... $ac_c" 1>&6 -echo "configure:1873: checking for yywrap in -lfl" >&5 -ac_lib_var=`echo fl'_'yywrap | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lfl $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1881 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char yywrap(); - -int main() { -yywrap() -; return 0; } -EOF -if { (eval echo configure:1892: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBFLEX=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBFLEX 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBFLEX=no -fi - - -echo $ac_n "checking for yywrap in -ll""... $ac_c" 1>&6 -echo "configure:1918: checking for yywrap in -ll" >&5 -ac_lib_var=`echo l'_'yywrap | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ll $LIBS" -cat > conftest.$ac_ext <<EOF -#line 1926 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char yywrap(); - -int main() { -yywrap() -; return 0; } -EOF -if { (eval echo configure:1937: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - HAVE_LIBLEX=yes ; cat >> confdefs.h <<\EOF -#define HAVE_LIBLEX 1 -EOF - -else - echo "$ac_t""no" 1>&6 -HAVE_LIBLEX=no -fi - - - -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 -echo "configure:1968: checking for $ac_hdr that defines DIR" >&5 -if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 1973 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <$ac_hdr> -int main() { -DIR *dirp = 0; -; return 0; } -EOF -if { (eval echo configure:1981: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - ac_header_dirent=$ac_hdr; break -else - echo "$ac_t""no" 1>&6 -fi -done -# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. -if test $ac_header_dirent = dirent.h; then -echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 -echo "configure:2006: checking for opendir in -ldir" >&5 -ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldir $LIBS" -cat > conftest.$ac_ext <<EOF -#line 2014 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char opendir(); - -int main() { -opendir() -; return 0; } -EOF -if { (eval echo configure:2025: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LIBS="$LIBS -ldir" -else - echo "$ac_t""no" 1>&6 -fi - -else -echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 -echo "configure:2047: checking for opendir in -lx" >&5 -ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lx $LIBS" -cat > conftest.$ac_ext <<EOF -#line 2055 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char opendir(); - -int main() { -opendir() -; return 0; } -EOF -if { (eval echo configure:2066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - LIBS="$LIBS -lx" -else - echo "$ac_t""no" 1>&6 -fi - -fi - -echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:2089: checking for ANSI C header files" >&5 -if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2094 "configure" -#include "confdefs.h" -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <float.h> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2102: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - ac_cv_header_stdc=yes -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. -cat > conftest.$ac_ext <<EOF -#line 2119 "configure" -#include "confdefs.h" -#include <string.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "memchr" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. -cat > conftest.$ac_ext <<EOF -#line 2137 "configure" -#include "confdefs.h" -#include <stdlib.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "free" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. -if test "$cross_compiling" = yes; then - : -else - cat > conftest.$ac_ext <<EOF -#line 2158 "configure" -#include "confdefs.h" -#include <ctype.h> -#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int main () { int i; for (i = 0; i < 256; i++) -if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); -exit (0); } - -EOF -if { (eval echo configure:2169: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then - : -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_header_stdc=no -fi -rm -fr conftest* -fi - -fi -fi - -echo "$ac_t""$ac_cv_header_stdc" 1>&6 -if test $ac_cv_header_stdc = yes; then - cat >> confdefs.h <<\EOF -#define STDC_HEADERS 1 -EOF - -fi - -echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 -echo "configure:2193: checking for sys/wait.h that is POSIX.1 compatible" >&5 -if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2198 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/wait.h> -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif -int main() { -int s; -wait (&s); -s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; -; return 0; } -EOF -if { (eval echo configure:2214: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_header_sys_wait_h=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_header_sys_wait_h=no -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 -if test $ac_cv_header_sys_wait_h = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_SYS_WAIT_H 1 -EOF - -fi - -for ac_hdr in fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h sys/fsuid.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2238: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2243 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2248: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - -for ac_hdr in features.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2279: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2284 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - -for ac_hdr in crypt.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2320: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2325 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2330: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - -for ac_hdr in ndbm.h db.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2361: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2366 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2371: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - -HAVE_NDBM_H=$ac_cv_header_ndbm_h - - -for ac_hdr in lastlog.h utmp.h utmpx.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2404: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2409 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2414: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - - -echo $ac_n "checking path to cracklib dictionary""... $ac_c" 1>&6 -echo "configure:2443: checking path to cracklib dictionary" >&5 -DICT_DIR_CANDIDATES="/usr/lib /usr/share/dict /usr/share/lib \ - /usr/local/lib /usr/local/share/lib" -DICT_FILE_CANDIDATES="pw_dict cracklib_dict" -CRACKLIB_DICTPATH="" -for d in $DICT_DIR_CANDIDATES ; do - for f in $DICT_FILE_CANDIDATES ; do - if test -r $d/$f.hwm ; then - CRACKLIB_DICTPATH=$d/$f - break 2 - elif test -r $d/dict/$f.hwm ; then - CRACKLIB_DICTPATH=$d/dict/$f - break 2 - fi - done -done -if test -z "$CRACKLIB_DICTPATH" ; then - echo "$ac_t""none found" 1>&6 -else - echo "$ac_t""$CRACKLIB_DICTPATH" 1>&6 -fi - - - -GCC_WARNINGS="-Wall -Wwrite-strings \ - -Wpointer-arith -Wcast-qual -Wcast-align \ - -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -Wshadow" - -if test "$GCC" = yes; then - CC=gcc ; -### May need per-OS attention -### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris. - case $OS in - linux) - OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic" - LD_D="gcc -shared -Xlinker -x" - WARNINGS="$GCC_WARNINGS" - PIC="-fPIC" - DYNTYPE=so - LD=ld - LD_L="$LD -x -shared" - RANLIB=ranlib - STRIP=strip - CC_STATIC="-Xlinker -export-dynamic" - ;; - sunos) - OS_CFLAGS="-ansi -pedantic" - LD_D="gcc -shared -Xlinker -x" - WARNINGS="$GCC_WARNINGS" - PIC="-fPIC" - DYNTYPE=so - LD=ld - LD_L="$LD -x -shared" - RANLIB=ranlib - STRIP=strip - CC_STATIC="-Xlinker -export-dynamic" - ;; - aix) - OS_CFLAGS="" - DYNTYPE=lo - LD=ld - LD_L=ld -bexpall -bM:SRE -bnoentry - LD_D="$LD_L" - RANLIB=ranlib - STRIP=strip - ;; - *) - OS_CFLAGS="" - ;; - esac -else -### -### Non-gcc needs attention on per-OS basis -### - case "$OS" in - darwin) -# add some stuff here (see sourceforge bug 534205) -# DOCDIR=/System/Documentation/Administration/Libraries/PAM -# MANDIR=/usr/share/man - ;; - solaris) - ### Support for Solaris-C - OS_CFLAGS="" - WARNINGS="" - PIC="-K pic" - LD=ld - LD_D="cc -z text -G -R." - LD_L="$LD_D" - RANLIB=ranlib - STRIP=strip - CC_STATIC= - ;; - irix*) - OSRELEASE=`uname -r` - if test "$OSRELEASE" = 6.5; then - OS_CFLAGS="" - WARNINGS="-fullwarn" - PIC= #PIC code is default for IRIX - LD="cc -shared" # modules friendly approach - LD_D="cc -shared" - LD_L="ld -G -z redlocsym" - RANLIB=echo - STRIP=strip - CC_STATIC= - else - echo "IRIX prior to 6.5 not allowed for" - exit - fi - ;; - *) echo "Native compiler on $OS is not yet supported" - exit - ;; - esac -fi - - - - - - - - - - - - -echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:2571: checking whether byte ordering is bigendian" >&5 -if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_cv_c_bigendian=unknown -# See if sys/param.h defines the BYTE_ORDER macro. -cat > conftest.$ac_ext <<EOF -#line 2578 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/param.h> -int main() { - -#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN - bogus endian macros -#endif -; return 0; } -EOF -if { (eval echo configure:2589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - # It does; now see whether it defined to BIG_ENDIAN or not. -cat > conftest.$ac_ext <<EOF -#line 2593 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/param.h> -int main() { - -#if BYTE_ORDER != BIG_ENDIAN - not big endian -#endif -; return 0; } -EOF -if { (eval echo configure:2604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_c_bigendian=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_c_bigendian=no -fi -rm -f conftest* -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 -fi -rm -f conftest* -if test $ac_cv_c_bigendian = unknown; then -if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext <<EOF -#line 2624 "configure" -#include "confdefs.h" -main () { - /* Are we little or big endian? From Harbison&Steele. */ - union - { - long l; - char c[sizeof (long)]; - } u; - u.l = 1; - exit (u.c[sizeof (long) - 1] == 1); -} -EOF -if { (eval echo configure:2637: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then - ac_cv_c_bigendian=no -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_c_bigendian=yes -fi -rm -fr conftest* -fi - -fi -fi - -echo "$ac_t""$ac_cv_c_bigendian" 1>&6 -if test $ac_cv_c_bigendian = yes; then - cat >> confdefs.h <<\EOF -#define WORDS_BIGENDIAN 1 -EOF - -fi - -echo $ac_n "checking for working const""... $ac_c" 1>&6 -echo "configure:2661: checking for working const" >&5 -if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2666 "configure" -#include "confdefs.h" - -int main() { - -/* Ultrix mips cc rejects this. */ -typedef int charset[2]; const charset x; -/* SunOS 4.1.1 cc rejects this. */ -char const *const *ccp; -char **p; -/* NEC SVR4.0.2 mips cc rejects this. */ -struct point {int x, y;}; -static struct point const zero = {0,0}; -/* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in an arm - of an if-expression whose if-part is not a constant expression */ -const char *g = "string"; -ccp = &g + (g ? g-g : 0); -/* HPUX 7.0 cc rejects these. */ -++ccp; -p = (char**) ccp; -ccp = (char const *const *) p; -{ /* SCO 3.2v4 cc rejects this. */ - char *t; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; -} -{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; -} -{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; -} -{ /* AIX XL C 1.02.0.0 rejects this saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; }; - struct s *b; b->j = 5; -} -{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; -} - -; return 0; } -EOF -if { (eval echo configure:2715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_c_const=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_c_const=no -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_c_const" 1>&6 -if test $ac_cv_c_const = no; then - cat >> confdefs.h <<\EOF -#define const -EOF - -fi - -echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:2736: checking for uid_t in sys/types.h" >&5 -if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2741 "configure" -#include "confdefs.h" -#include <sys/types.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "uid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_uid_t=yes -else - rm -rf conftest* - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi - -echo "$ac_t""$ac_cv_type_uid_t" 1>&6 -if test $ac_cv_type_uid_t = no; then - cat >> confdefs.h <<\EOF -#define uid_t int -EOF - - cat >> confdefs.h <<\EOF -#define gid_t int -EOF - -fi - -echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:2770: checking for off_t" >&5 -if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2775 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#include <stddef.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_off_t=yes -else - rm -rf conftest* - ac_cv_type_off_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_off_t" 1>&6 -if test $ac_cv_type_off_t = no; then - cat >> confdefs.h <<\EOF -#define off_t long -EOF - -fi - -echo $ac_n "checking for pid_t""... $ac_c" 1>&6 -echo "configure:2803: checking for pid_t" >&5 -if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2808 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#include <stddef.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_pid_t=yes -else - rm -rf conftest* - ac_cv_type_pid_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_pid_t" 1>&6 -if test $ac_cv_type_pid_t = no; then - cat >> confdefs.h <<\EOF -#define pid_t int -EOF - -fi - -echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:2836: checking for size_t" >&5 -if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2841 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#include <stddef.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_size_t=yes -else - rm -rf conftest* - ac_cv_type_size_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_size_t" 1>&6 -if test $ac_cv_type_size_t = no; then - cat >> confdefs.h <<\EOF -#define size_t unsigned -EOF - -fi - -echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 -echo "configure:2869: checking whether time.h and sys/time.h may both be included" >&5 -if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2874 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/time.h> -#include <time.h> -int main() { -struct tm *tp; -; return 0; } -EOF -if { (eval echo configure:2883: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_header_time=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_header_time=no -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_header_time" 1>&6 -if test $ac_cv_header_time = yes; then - cat >> confdefs.h <<\EOF -#define TIME_WITH_SYS_TIME 1 -EOF - -fi - -echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 -echo "configure:2904: checking whether struct tm is in sys/time.h or time.h" >&5 -if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2909 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <time.h> -int main() { -struct tm *tp; tp->tm_sec; -; return 0; } -EOF -if { (eval echo configure:2917: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_struct_tm=time.h -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_struct_tm=sys/time.h -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_struct_tm" 1>&6 -if test $ac_cv_struct_tm = sys/time.h; then - cat >> confdefs.h <<\EOF -#define TM_IN_SYS_TIME 1 -EOF - -fi - - -echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 -echo "configure:2939: checking type of array argument to getgroups" >&5 -if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - ac_cv_type_getgroups=cross -else - cat > conftest.$ac_ext <<EOF -#line 2947 "configure" -#include "confdefs.h" - -/* Thanks to Mike Rendell for this test. */ -#include <sys/types.h> -#define NGID 256 -#undef MAX -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -main() -{ - gid_t gidset[NGID]; - int i, n; - union { gid_t gval; long lval; } val; - - val.lval = -1; - for (i = 0; i < NGID; i++) - gidset[i] = val.gval; - n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, - gidset); - /* Exit non-zero if getgroups seems to require an array of ints. This - happens when gid_t is short but getgroups modifies an array of ints. */ - exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); -} - -EOF -if { (eval echo configure:2972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then - ac_cv_type_getgroups=gid_t -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_type_getgroups=int -fi -rm -fr conftest* -fi - -if test $ac_cv_type_getgroups = cross; then - cat > conftest.$ac_ext <<EOF -#line 2986 "configure" -#include "confdefs.h" -#include <unistd.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_getgroups=gid_t -else - rm -rf conftest* - ac_cv_type_getgroups=int -fi -rm -f conftest* - -fi -fi - -echo "$ac_t""$ac_cv_type_getgroups" 1>&6 -cat >> confdefs.h <<EOF -#define GETGROUPS_T $ac_cv_type_getgroups -EOF - - -if test $ac_cv_prog_gcc = yes; then - echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 -echo "configure:3011: checking whether ${CC-cc} needs -traditional" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_pattern="Autoconf.*'x'" - cat > conftest.$ac_ext <<EOF -#line 3017 "configure" -#include "confdefs.h" -#include <sgtty.h> -Autoconf TIOCGETP -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "$ac_pattern" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_prog_gcc_traditional=yes -else - rm -rf conftest* - ac_cv_prog_gcc_traditional=no -fi -rm -f conftest* - - - if test $ac_cv_prog_gcc_traditional = no; then - cat > conftest.$ac_ext <<EOF -#line 3035 "configure" -#include "confdefs.h" -#include <termio.h> -Autoconf TCGETA -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "$ac_pattern" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_prog_gcc_traditional=yes -fi -rm -f conftest* - - fi -fi - -echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 - if test $ac_cv_prog_gcc_traditional = yes; then - CC="$CC -traditional" - fi -fi - -echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 -echo "configure:3057: checking for 8-bit clean memcmp" >&5 -if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - ac_cv_func_memcmp_clean=no -else - cat > conftest.$ac_ext <<EOF -#line 3065 "configure" -#include "confdefs.h" - -main() -{ - char c0 = 0x40, c1 = 0x80, c2 = 0x81; - exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); -} - -EOF -if { (eval echo configure:3075: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then - ac_cv_func_memcmp_clean=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_func_memcmp_clean=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 -test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" - -echo $ac_n "checking for vprintf""... $ac_c" 1>&6 -echo "configure:3093: checking for vprintf" >&5 -if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 3098 "configure" -#include "confdefs.h" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char vprintf(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char vprintf(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_vprintf) || defined (__stub___vprintf) -choke me -#else -vprintf(); -#endif - -; return 0; } -EOF -if { (eval echo configure:3121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func_vprintf=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_vprintf=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then - echo "$ac_t""yes" 1>&6 - cat >> confdefs.h <<\EOF -#define HAVE_VPRINTF 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi - -if test "$ac_cv_func_vprintf" != yes; then -echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 -echo "configure:3145: checking for _doprnt" >&5 -if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 3150 "configure" -#include "confdefs.h" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char _doprnt(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char _doprnt(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub__doprnt) || defined (__stub____doprnt) -choke me -#else -_doprnt(); -#endif - -; return 0; } -EOF -if { (eval echo configure:3173: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func__doprnt=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func__doprnt=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then - echo "$ac_t""yes" 1>&6 - cat >> confdefs.h <<\EOF -#define HAVE_DOPRNT 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi - -fi - -for ac_func in gethostname gettimeofday mkdir select strcspn strdup strerror strspn strstr strtol uname -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3200: checking for $ac_func" >&5 -if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 3205 "configure" -#include "confdefs.h" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char $ac_func(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if { (eval echo configure:3228: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <<EOF -#define $ac_tr_func 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - -for ac_func in getpwnam_r getgrnam_r -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3256: checking for $ac_func" >&5 -if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 3261 "configure" -#include "confdefs.h" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char $ac_func(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if { (eval echo configure:3284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <<EOF -#define $ac_tr_func 1 -EOF - -else - echo "$ac_t""no" 1>&6 -fi -done - - -# Extract the first word of "sgml2txt", so it can be a program name with args. -set dummy sgml2txt; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3312: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2TXT'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$HAVE_SGML2TXT"; then - ac_cv_prog_HAVE_SGML2TXT="$HAVE_SGML2TXT" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_HAVE_SGML2TXT="yes" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_HAVE_SGML2TXT" && ac_cv_prog_HAVE_SGML2TXT="no" -fi -fi -HAVE_SGML2TXT="$ac_cv_prog_HAVE_SGML2TXT" -if test -n "$HAVE_SGML2TXT"; then - echo "$ac_t""$HAVE_SGML2TXT" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -# Extract the first word of "sgml2html", so it can be a program name with args. -set dummy sgml2html; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3342: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2HTML'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$HAVE_SGML2HTML"; then - ac_cv_prog_HAVE_SGML2HTML="$HAVE_SGML2HTML" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_HAVE_SGML2HTML="yes" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_HAVE_SGML2HTML" && ac_cv_prog_HAVE_SGML2HTML="no" -fi -fi -HAVE_SGML2HTML="$ac_cv_prog_HAVE_SGML2HTML" -if test -n "$HAVE_SGML2HTML"; then - echo "$ac_t""$HAVE_SGML2HTML" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -# Extract the first word of "sgml2latex", so it can be a program name with args. -set dummy sgml2latex; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3372: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2LATEX'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$HAVE_SGML2LATEX"; then - ac_cv_prog_HAVE_SGML2LATEX="$HAVE_SGML2LATEX" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_HAVE_SGML2LATEX="yes" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_HAVE_SGML2LATEX" && ac_cv_prog_HAVE_SGML2LATEX="no" -fi -fi -HAVE_SGML2LATEX="$ac_cv_prog_HAVE_SGML2LATEX" -if test -n "$HAVE_SGML2LATEX"; then - echo "$ac_t""$HAVE_SGML2LATEX" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -if test $HAVE_SGML2LATEX = "yes" ; then - if sgml2latex -h | grep -e --paper | grep ' -p ' > /dev/null ; then - PSER="sgml2latex -o ps" - else - PSER="sgml2latex -p" - fi - # Extract the first word of "ps2pdf", so it can be a program name with args. -set dummy ps2pdf; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3408: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_HAVE_PS2PDF'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$HAVE_PS2PDF"; then - ac_cv_prog_HAVE_PS2PDF="$HAVE_PS2PDF" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_HAVE_PS2PDF="yes" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_HAVE_PS2PDF" && ac_cv_prog_HAVE_PS2PDF="no" -fi -fi -HAVE_PS2PDF="$ac_cv_prog_HAVE_PS2PDF" -if test -n "$HAVE_PS2PDF"; then - echo "$ac_t""$HAVE_PS2PDF" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -else - # Extract the first word of "sgml2ps", so it can be a program name with args. -set dummy sgml2ps; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3439: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_HAVE_SGML2PS'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$HAVE_SGML2PS"; then - ac_cv_prog_HAVE_SGML2PS="$HAVE_SGML2PS" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_HAVE_SGML2PS="yes" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_HAVE_SGML2PS" && ac_cv_prog_HAVE_SGML2PS="no" -fi -fi -HAVE_SGML2PS="$ac_cv_prog_HAVE_SGML2PS" -if test -n "$HAVE_SGML2PS"; then - echo "$ac_t""$HAVE_SGML2PS" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - if test $HAVE_SGML2PS = yes ; then - PSER="sgml2ps" - fi -fi - - - -trap '' 1 2 15 -cat > confcache <<\EOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs. It is not useful on other systems. -# If it contains results you don't want to keep, you may remove or edit it. -# -# By default, configure uses ./config.cache as the cache file, -# creating it if it does not exist already. You can give configure -# the --cache-file=FILE option to use a different cache file; that is -# what configure does when it calls configure scripts in -# subdirectories, so they share the cache. -# Giving --cache-file=/dev/null disables caching, for debugging configure. -# config.status only pays attention to the cache file if you give it the -# --recheck option to rerun configure. -# -EOF -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, don't put newlines in cache variables' values. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -(set) 2>&1 | - case `(ac_space=' '; set | grep ac_space) 2>&1` in - *ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote substitution - # turns \\\\ into \\, and sed turns \\ into \). - sed -n \ - -e "s/'/'\\\\''/g" \ - -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" - ;; - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' - ;; - esac >> confcache -if cmp -s $cache_file confcache; then - : -else - if test -w $cache_file; then - echo "updating cache $cache_file" - cat confcache > $cache_file - else - echo "not updating unwritable cache $cache_file" - fi -fi -rm -f confcache - -trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Any assignment to VPATH causes Sun make to only execute -# the first set of double-colon rules, so remove it if not needed. -# If there is a colon in the path, we need to keep it. -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' -fi - -trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 - -DEFS=-DHAVE_CONFIG_H - -# Without the "./", some shells look in PATH for config.status. -: ${CONFIG_STATUS=./config.status} - -echo creating $CONFIG_STATUS -rm -f $CONFIG_STATUS -cat > $CONFIG_STATUS <<EOF -#! /bin/sh -# Generated automatically by configure. -# Run this file to recreate the current configuration. -# This directory was configured as follows, -# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# -# $0 $ac_configure_args -# -# Compiler output produced by configure, useful for debugging -# configure, is in ./config.log if it exists. - -ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" -for ac_option -do - case "\$ac_option" in - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" - exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; - -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.13" - exit 0 ;; - -help | --help | --hel | --he | --h) - echo "\$ac_cs_usage"; exit 0 ;; - *) echo "\$ac_cs_usage"; exit 1 ;; - esac -done - -ac_given_srcdir=$srcdir - -trap 'rm -fr `echo "Make.Rules _pam_aconf.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 -EOF -cat >> $CONFIG_STATUS <<EOF - -# Protect against being on the right side of a sed subst in config.status. -sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; - s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF -$ac_vpsub -$extrasub -s%@SHELL@%$SHELL%g -s%@CFLAGS@%$CFLAGS%g -s%@CPPFLAGS@%$CPPFLAGS%g -s%@CXXFLAGS@%$CXXFLAGS%g -s%@FFLAGS@%$FFLAGS%g -s%@DEFS@%$DEFS%g -s%@LDFLAGS@%$LDFLAGS%g -s%@LIBS@%$LIBS%g -s%@exec_prefix@%$exec_prefix%g -s%@prefix@%$prefix%g -s%@program_transform_name@%$program_transform_name%g -s%@bindir@%$bindir%g -s%@sbindir@%$sbindir%g -s%@libexecdir@%$libexecdir%g -s%@datadir@%$datadir%g -s%@sysconfdir@%$sysconfdir%g -s%@sharedstatedir@%$sharedstatedir%g -s%@localstatedir@%$localstatedir%g -s%@libdir@%$libdir%g -s%@includedir@%$includedir%g -s%@oldincludedir@%$oldincludedir%g -s%@infodir@%$infodir%g -s%@mandir@%$mandir%g -s%@LIBPAM_VERSION_MAJOR@%$LIBPAM_VERSION_MAJOR%g -s%@LIBPAM_VERSION_MINOR@%$LIBPAM_VERSION_MINOR%g -s%@LOCALSRCDIR@%$LOCALSRCDIR%g -s%@LOCALOBJDIR@%$LOCALOBJDIR%g -s%@OS@%$OS%g -s%@CONF_CFLAGS@%$CONF_CFLAGS%g -s%@MKDIR@%$MKDIR%g -s%@SHLIBMODE@%$SHLIBMODE%g -s%@USESONAME@%$USESONAME%g -s%@SOSWITCH@%$SOSWITCH%g -s%@NEEDSONAME@%$NEEDSONAME%g -s%@LDCONFIG@%$LDCONFIG%g -s%@INSTALL@%$INSTALL%g -s%@CC@%$CC%g -s%@YACC@%$YACC%g -s%@LEX@%$LEX%g -s%@LEXLIB@%$LEXLIB%g -s%@LN_S@%$LN_S%g -s%@SET_MAKE@%$SET_MAKE%g -s%@WITH_DEBUG@%$WITH_DEBUG%g -s%@WITH_MEMORY_DEBUG@%$WITH_MEMORY_DEBUG%g -s%@WITH_LIBDEBUG@%$WITH_LIBDEBUG%g -s%@FAKEROOT@%$FAKEROOT%g -s%@SECUREDIR@%$SECUREDIR%g -s%@SCONFIGDIR@%$SCONFIGDIR%g -s%@SUPLEMENTED@%$SUPLEMENTED%g -s%@INCLUDEDIR@%$INCLUDEDIR%g -s%@DOCDIR@%$DOCDIR%g -s%@MANDIR@%$MANDIR%g -s%@WITH_PAMLOCKING@%$WITH_PAMLOCKING%g -s%@PAM_READ_BOTH_CONFS@%$PAM_READ_BOTH_CONFS%g -s%@STATIC_LIBPAM@%$STATIC_LIBPAM%g -s%@DYNAMIC_LIBPAM@%$DYNAMIC_LIBPAM%g -s%@DYNAMIC@%$DYNAMIC%g -s%@STATIC@%$STATIC%g -s%@WITH_LCKPWDF@%$WITH_LCKPWDF%g -s%@CPP@%$CPP%g -s%@PAM_NEEDS_LIBC@%$PAM_NEEDS_LIBC%g -s%@HAVE_LCKPWDF@%$HAVE_LCKPWDF%g -s%@LIBDL@%$LIBDL%g -s%@HAVE_LIBCRACK@%$HAVE_LIBCRACK%g -s%@HAVE_LIBCRYPT@%$HAVE_LIBCRYPT%g -s%@HAVE_LIBUTIL@%$HAVE_LIBUTIL%g -s%@HAVE_LIBNDBM@%$HAVE_LIBNDBM%g -s%@HAVE_LIBDB@%$HAVE_LIBDB%g -s%@HAVE_LIBFL@%$HAVE_LIBFL%g -s%@HAVE_LIBNSL@%$HAVE_LIBNSL%g -s%@HAVE_LIBPWDB@%$HAVE_LIBPWDB%g -s%@HAVE_LIBFLEX@%$HAVE_LIBFLEX%g -s%@HAVE_LIBLEX@%$HAVE_LIBLEX%g -s%@HAVE_NDBM_H@%$HAVE_NDBM_H%g -s%@CRACKLIB_DICTPATH@%$CRACKLIB_DICTPATH%g -s%@DYNTYPE@%$DYNTYPE%g -s%@OS_CFLAGS@%$OS_CFLAGS%g -s%@WARNINGS@%$WARNINGS%g -s%@PIC@%$PIC%g -s%@LD@%$LD%g -s%@LD_D@%$LD_D%g -s%@LD_L@%$LD_L%g -s%@RANLIB@%$RANLIB%g -s%@STRIP@%$STRIP%g -s%@CC_STATIC@%$CC_STATIC%g -s%@LIBOBJS@%$LIBOBJS%g -s%@HAVE_SGML2TXT@%$HAVE_SGML2TXT%g -s%@HAVE_SGML2HTML@%$HAVE_SGML2HTML%g -s%@HAVE_SGML2LATEX@%$HAVE_SGML2LATEX%g -s%@HAVE_PS2PDF@%$HAVE_PS2PDF%g -s%@HAVE_SGML2PS@%$HAVE_SGML2PS%g -s%@PSER@%$PSER%g -s%@PS2PDF@%$PS2PDF%g - -CEOF -EOF - -cat >> $CONFIG_STATUS <<\EOF - -# Split the substitutions into bite-sized pieces for seds with -# small command number limits, like on Digital OSF/1 and HP-UX. -ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. -ac_file=1 # Number of current file. -ac_beg=1 # First line for current file. -ac_end=$ac_max_sed_cmds # Line after last line for current file. -ac_more_lines=: -ac_sed_cmds="" -while $ac_more_lines; do - if test $ac_beg -gt 1; then - sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file - else - sed "${ac_end}q" conftest.subs > conftest.s$ac_file - fi - if test ! -s conftest.s$ac_file; then - ac_more_lines=false - rm -f conftest.s$ac_file - else - if test -z "$ac_sed_cmds"; then - ac_sed_cmds="sed -f conftest.s$ac_file" - else - ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" - fi - ac_file=`expr $ac_file + 1` - ac_beg=$ac_end - ac_end=`expr $ac_end + $ac_max_sed_cmds` - fi -done -if test -z "$ac_sed_cmds"; then - ac_sed_cmds=cat -fi -EOF - -cat >> $CONFIG_STATUS <<EOF - -CONFIG_FILES=\${CONFIG_FILES-"Make.Rules"} -EOF -cat >> $CONFIG_STATUS <<\EOF -for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. - - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" - # A "../" for each directory in $ac_dir_suffix. - ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` - else - ac_dir_suffix= ac_dots= - fi - - case "$ac_given_srcdir" in - .) srcdir=. - if test -z "$ac_dots"; then top_srcdir=. - else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; - /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; - *) # Relative path. - srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" - top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - - - echo creating "$ac_file" - rm -f "$ac_file" - configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." - case "$ac_file" in - *Makefile*) ac_comsub="1i\\ -# $configure_input" ;; - *) ac_comsub= ;; - esac - - ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` - sed -e "$ac_comsub -s%@configure_input@%$configure_input%g -s%@srcdir@%$srcdir%g -s%@top_srcdir@%$top_srcdir%g -" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file -fi; done -rm -f conftest.s* - -# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where -# NAME is the cpp macro being defined and VALUE is the value it is being given. -# -# ac_d sets the value in "#define NAME VALUE" lines. -ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' -ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' -ac_dC='\3' -ac_dD='%g' -# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". -ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_uB='\([ ]\)%\1#\2define\3' -ac_uC=' ' -ac_uD='\4%g' -# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". -ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_eB='$%\1#\2define\3' -ac_eC=' ' -ac_eD='%g' - -if test "${CONFIG_HEADERS+set}" != set; then -EOF -cat >> $CONFIG_STATUS <<EOF - CONFIG_HEADERS="_pam_aconf.h" -EOF -cat >> $CONFIG_STATUS <<\EOF -fi -for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - echo creating $ac_file - - rm -f conftest.frag conftest.in conftest.out - ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` - cat $ac_file_inputs > conftest.in - -EOF - -# Transform confdefs.h into a sed script conftest.vals that substitutes -# the proper values into config.h.in to produce config.h. And first: -# Protect against being on the right side of a sed subst in config.status. -# Protect against being in an unquoted here document in config.status. -rm -f conftest.vals -cat > conftest.hdr <<\EOF -s/[\\&%]/\\&/g -s%[\\$`]%\\&%g -s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp -s%ac_d%ac_u%gp -s%ac_u%ac_e%gp -EOF -sed -n -f conftest.hdr confdefs.h > conftest.vals -rm -f conftest.hdr - -# This sed command replaces #undef with comments. This is necessary, for -# example, in the case of _POSIX_SOURCE, which is predefined and required -# on some systems where configure will not decide to define it. -cat >> conftest.vals <<\EOF -s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% -EOF - -# Break up conftest.vals because some shells have a limit on -# the size of here documents, and old seds have small limits too. - -rm -f conftest.tail -while : -do - ac_lines=`grep -c . conftest.vals` - # grep -c gives empty output for an empty file on some AIX systems. - if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi - # Write a limited-size here document to conftest.frag. - echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS - sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS - echo 'CEOF - sed -f conftest.frag conftest.in > conftest.out - rm -f conftest.in - mv conftest.out conftest.in -' >> $CONFIG_STATUS - sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail - rm -f conftest.vals - mv conftest.tail conftest.vals -done -rm -f conftest.vals - -cat >> $CONFIG_STATUS <<\EOF - rm -f conftest.frag conftest.h - echo "/* $ac_file. Generated automatically by configure. */" > conftest.h - cat conftest.in >> conftest.h - rm -f conftest.in - if cmp -s $ac_file conftest.h 2>/dev/null; then - echo "$ac_file is unchanged" - rm -f conftest.h - else - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - fi - rm -f $ac_file - mv conftest.h $ac_file - fi -fi; done - -EOF -cat >> $CONFIG_STATUS <<EOF - -EOF -cat >> $CONFIG_STATUS <<\EOF - -exit 0 -EOF -chmod +x $CONFIG_STATUS -rm -fr confdefs* $ac_clean_files -test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 - diff --git a/configure.in b/configure.in deleted file mode 100644 index 8da11c85..00000000 --- a/configure.in +++ /dev/null @@ -1,439 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -AC_INIT(conf/pam_conv1/pam_conv.y) - -dnl The configuration header file -AC_CONFIG_HEADER(_pam_aconf.h) - -dnl -dnl Release specific -dnl - -LIBPAM_VERSION_MAJOR=0 -LIBPAM_VERSION_MINOR=76 - -AC_SUBST(LIBPAM_VERSION_MAJOR) -AC_SUBST(LIBPAM_VERSION_MINOR) -AC_DEFINE(LIBPAM_VERSION_MAJOR) -AC_DEFINE(LIBPAM_VERSION_MINOR) - -dnl -dnl By default, everything under PAM is installed under the root fs. -dnl - -AC_PREFIX_DEFAULT() - -dnl -dnl Useful info (believed to be portable) - in the future -dnl the LOCALSRCDIR and LOCALOBJDIRs may be different -dnl -LOCALSRCDIR=`/bin/pwd` ; AC_SUBST(LOCALSRCDIR) -LOCALOBJDIR=`/bin/pwd` ; AC_SUBST(LOCALOBJDIR) -OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` -AC_SUBST(OS) - -dnl -dnl Rules needed for the following (hardcoded Linux defaults for now) -dnl - -CONF_CFLAGS= ; AC_SUBST(CONF_CFLAGS) -MKDIR="mkdir -p" ; AC_SUBST(MKDIR) - -SHLIBMODE=755 ; AC_SUBST(SHLIBMODE) - -dnl These are most likely platform specific - I think HPUX differs -USESONAME=yes ; AC_SUBST(USESONAME) -SOSWITCH=-soname ; AC_SUBST(SOSWITCH) -NEEDSONAME=no ; AC_SUBST(NEEDSONAME) -LDCONFIG=/sbin/ldconfig ; AC_SUBST(LDCONFIG) - -dnl ### Should enable this INSTALL detection. -dnl ### Would need to distribute GNU's config.guess and config.sub -dnl AC_PROG_INSTALL -if test "$OS" = "aix"; then - INSTALL=/usr/ucb/install -c -else - INSTALL=/usr/bin/install -fi -AC_SUBST(INSTALL) - -dnl Checks for programs. -AC_PROG_CC -dnl ### AC_PROG_CXX -AC_PROG_YACC -AC_PROG_LEX -dnl AC_PROG_INSTALL -AC_PROG_LN_S -AC_PROG_MAKE_SET - -dnl -dnl options and defaults -dnl - -dnl lots of debugging information goes to /tmp/pam-debug.log -AC_ARG_ENABLE(debug, -[ --enable-debug specify you are building with debugging on], - WITH_DEBUG=yes ; AC_DEFINE(DEBUG) , WITH_DEBUG=no) -AC_SUBST(WITH_DEBUG) - -AC_ARG_ENABLE(memory-debug, -[ --enable-memory-debug specify you want every malloc etc. call tracked], - WITH_MEMORY_DEBUG=yes ; AC_DEFINE(MEMORY_DEBUG) , WITH_MEMORY_DEBUG=no) -AC_SUBST(WITH_MEMORY_DEBUG) - -dnl build specially named libraries (for debugging purposes) -AC_ARG_ENABLE(libdebug, -[ --enable-libdebug specify you are building debugging libraries], - WITH_LIBDEBUG=yes ; AC_DEFINE(WITH_LIBDEBUG) , WITH_LIBDEBUG=no) -AC_SUBST(WITH_LIBDEBUG) - -dnl packaging convenience -AC_ARG_ENABLE(fakeroot, -[ --enable-fakeroot=<path to packaging directory>], FAKEROOT=$enableval) -AC_SUBST(FAKEROOT) - -AC_ARG_ENABLE(securedir, -[ --enable-securedir=<path to location of PAMs> [default \$libdir/security]], - SECUREDIR=$enableval, SECUREDIR=$libdir/security) -AC_SUBST(SECUREDIR) - -AC_ARG_ENABLE(sconfigdir, -[ --enable-sconfigdir=<path to module conf files> [default \$sysconfdir/security]], - SCONFIGDIR=$enableval, SCONFIGDIR=$sysconfdir/security) -AC_SUBST(SCONFIGDIR) - -AC_ARG_ENABLE(suplementedir, -[ --enable-suplementedir=<path to module helper binaries> [default \$sbindir]], - SUPLEMENTED=$enableval, SUPLEMENTED=$sbindir) -AC_SUBST(SUPLEMENTED) - -AC_ARG_ENABLE(includedir, -[ --enable-includedir=<path to include location> - where to put <security>], - INCLUDEDIR=$enableval, INCLUDEDIR=/usr/include) -AC_SUBST(INCLUDEDIR) - -AC_ARG_ENABLE(docdir, -[ --enable-docdir=<path to store documentation in - /usr/share/doc/pam>], - DOCDIR=$enableval, DOCDIR=/usr/share/doc/pam) -AC_SUBST(DOCDIR) - -AC_ARG_ENABLE(mandir, -[ --enable-mandir=<path to store manuals in - /usr/share/man>], - MANDIR=$enableval, MANDIR=/usr/share/man) -AC_SUBST(MANDIR) - -AC_ARG_ENABLE(pamlocking, -[ --enable-pamlocking configure libpam to observe a global authentication lock], - WITH_PAMLOCKING=yes ; AC_DEFINE(PAM_LOCKING) , WITH_PAMLOCKING=no) -AC_SUBST(WITH_PAMLOCKING) - -AC_ARG_ENABLE(uglyhack, -[ --enable-uglyhack configure libpam to try to honor old pam_strerror syntax], - AC_DEFINE(UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT)) - -AC_ARG_ENABLE(read-both-confs, -[ --enable-read-both-confs read both /etc/pam.d and /etc/pam.conf files], - AC_DEFINE(PAM_READ_BOTH_CONFS)) -AC_SUBST(PAM_READ_BOTH_CONFS) - -AC_ARG_ENABLE(static-libpam, [ --enable-static-libpam build a libpam.a library], - STATIC_LIBPAM=yes , STATIC_LIBPAM=no) -AC_SUBST(STATIC_LIBPAM) - -AC_ARG_ENABLE(dynamic-libpam, -[ --disable-dynamic-libpam do not build a shared libpam library], - DYNAMIC_LIBPAM=no, DYNAMIC_LIBPAM=yes) -AC_SUBST(DYNAMIC_LIBPAM) - -DYNAMIC=-DPAM_DYNAMIC -AC_SUBST(DYNAMIC) - -AC_ARG_ENABLE(static-modules, -[ --enable-static-modules do not make the modules dynamically loadable], - STATIC=-DPAM_STATIC) -AC_SUBST(STATIC) - -AC_ARG_ENABLE(lckpwdf, -[ --disable-lckpwdf do not use the lckpwdf function], - WITH_LCKPWDF=no, WITH_LCKPWDF=yes) -AC_SUBST(WITH_LCKPWDF) - -AC_CHECK_HEADERS(paths.h) -AC_ARG_WITH(mailspool, -[ --with-mailspool path to mail spool directory - [default _PATH_MAILDIR if defined in paths.h, otherwise /var/spool/mail]], -with_mailspool=${withval}) -if test x$with_mailspool != x ; then - pam_mail_spool="\"$with_mailspool\"" -else - AC_TRY_RUN([ -#include <paths.h> -int main() { -#ifdef _PATH_MAILDIR -exit(0); -#else -exit(1); -#endif -}], pam_mail_spool="_PATH_MAILDIR", -pam_mail_spool="\"/var/spool/mail\"", -pam_mail_spool="\"/var/spool/mail\"") -fi -AC_DEFINE_UNQUOTED(PAM_PATH_MAILDIR, $pam_mail_spool) - -dnl Checks for libraries. -AC_CHECK_LIB(c, __libc_sched_setscheduler, PAM_NEEDS_LIBC=, PAM_NEEDS_LIBC=-lc) -AC_SUBST(PAM_NEEDS_LIBC) - -dnl Checks for the existence of lckpwdf in libc -AC_CHECK_LIB(c, lckpwdf, HAVE_LCKPWDF=yes, HAVE_LCKPWDF=no) -AC_SUBST(HAVE_LCKPWDF) - -dnl Checks for the existence of libdl - on BSD and Tru64 its part of libc -AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl) -AC_SUBST(LIBDL) - -dnl -dnl At least on Solaris, the existing libcrack must be dynamic. -dnl Ought to introduce a check for this. -dnl -AC_CHECK_LIB(crack, FascistCheck, HAVE_LIBCRACK=yes ; AC_DEFINE(HAVE_LIBCRACK), - HAVE_LIBCRACK=no) -AC_SUBST(HAVE_LIBCRACK) - -AC_CHECK_LIB(crypt, fcrypt, HAVE_LIBCRYPT=yes ; AC_DEFINE(HAVE_LIBCRYPT), - HAVE_LIBCRYPT=no) -AC_SUBST(HAVE_LIBCRYPT) -AC_CHECK_LIB(util, logwtmp, HAVE_LIBUTIL=yes ; AC_DEFINE(HAVE_LIBUTIL), - HAVE_LIBUTIL=no) -AC_SUBST(HAVE_LIBUTIL) -AC_CHECK_LIB(ndbm, dbm_store, HAVE_LIBNDBM=yes ; AC_DEFINE(HAVE_LIBNDBM), - HAVE_LIBNDBM=no) -AC_SUBST(HAVE_LIBNDBM) -AC_CHECK_LIB(db, dbm_store, HAVE_LIBDB=yes ; AC_DEFINE(HAVE_LIBDB), - HAVE_LIBDB=no) -if test x$HAVE_LIBDB != xyes ; then - AC_CHECK_LIB(db, db_create, HAVE_LIBDB=yes ; AC_DEFINE(HAVE_LIBDB), - HAVE_LIBDB=no) -fi -AC_SUBST(HAVE_LIBDB) -AC_CHECK_LIB(fl, yylex, yyterminate, HAVE_LIBFL=yes ; AC_DEFINE(HAVE_LIBFL), - HAVE_LIBFL=no) -AC_SUBST(HAVE_LIBFL) -AC_CHECK_LIB(nsl, yp_maplist, HAVE_LIBNSL=yes ; AC_DEFINE(HAVE_LIBNSL), - HAVE_LIBNSL=no) -AC_SUBST(HAVE_LIBNSL) -AC_CHECK_LIB(pwdb, pwdb_db_name, HAVE_LIBPWDB=yes ; AC_DEFINE(HAVE_LIBPWDB), - HAVE_LIBPWDB=no) -AC_SUBST(HAVE_LIBPWDB) -AC_CHECK_LIB(fl, yywrap, HAVE_LIBFLEX=yes ; AC_DEFINE(HAVE_LIBFLEX), - HAVE_LIBFLEX=no) -AC_SUBST(HAVE_LIBFLEX) -AC_CHECK_LIB(l, yywrap, HAVE_LIBLEX=yes ; AC_DEFINE(HAVE_LIBLEX), - HAVE_LIBLEX=no) -AC_SUBST(HAVE_LIBLEX) - -dnl Checks for header files. -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h sys/fsuid.h) - -dnl Linux wants features.h in some of the source files. -AC_CHECK_HEADERS(features.h) - -dnl For module/pam_cracklib -AC_CHECK_HEADERS(crypt.h) - -dnl For module/pam_userdb -AC_CHECK_HEADERS(ndbm.h db.h) -dnl I suspect the following two lines are a hack. -HAVE_NDBM_H=$ac_cv_header_ndbm_h -AC_SUBST(HAVE_NDBM_H) - -dnl For module/pam_lastlog -AC_CHECK_HEADERS(lastlog.h utmp.h utmpx.h) - -dnl This following rule should be made conditional upon HAVE_LIBCRYPT -dnl being found. - -dnl Look for cracklib dictionary -AC_MSG_CHECKING(path to cracklib dictionary) -DICT_DIR_CANDIDATES="/usr/lib /usr/share/dict /usr/share/lib \ - /usr/local/lib /usr/local/share/lib" -DICT_FILE_CANDIDATES="pw_dict cracklib_dict" -CRACKLIB_DICTPATH="" -for d in $DICT_DIR_CANDIDATES ; do - for f in $DICT_FILE_CANDIDATES ; do - if test -r $d/$f.hwm ; then - CRACKLIB_DICTPATH=$d/$f - break 2 - elif test -r $d/dict/$f.hwm ; then - CRACKLIB_DICTPATH=$d/dict/$f - break 2 - fi - done -done -if test -z "$CRACKLIB_DICTPATH" ; then - AC_MSG_RESULT(none found) -else - AC_MSG_RESULT($CRACKLIB_DICTPATH) -fi -AC_SUBST(CRACKLIB_DICTPATH) - -dnl Set FLAGS, linker options etc. depending on C compiler. -dnl gcc is tested and much preferred; others less so, if at all -dnl -dnl If compiling with gcc, linking is also supposed to be done with gcc; -dnl since we use linker-specific arguments, we may not gain anything by -dnl switching LD_L over, but I think we can use LD_D as-is. -dnl -dnl For the moment, gcc is enforced above at "CC=gcc". -dnl -dnl There is an issue over _POSIX_SOURCE _BSD_SOURCE and _GNU_SOURCE . -dnl The original "Linux-PAM" had blanket inclusion. But portability -dnl requires their default absence: if particular OSes require them, -dnl this should be done selectively. - -GCC_WARNINGS="-Wall -Wwrite-strings \ - -Wpointer-arith -Wcast-qual -Wcast-align \ - -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -Wshadow" - -if test "$GCC" = yes; then - CC=gcc ; AC_SUBST(CC) -### May need per-OS attention -### Example: -D_POSIX_SOURCE: needed on Linux but harms Solaris. - case $OS in - linux) - OS_CFLAGS="-ansi -D_POSIX_SOURCE -pedantic" - LD_D="gcc -shared -Xlinker -x" - WARNINGS="$GCC_WARNINGS" - PIC="-fPIC" - DYNTYPE=so - LD=ld - LD_L="$LD -x -shared" - RANLIB=ranlib - STRIP=strip - CC_STATIC="-Xlinker -export-dynamic" - ;; - sunos) - OS_CFLAGS="-ansi -pedantic" - LD_D="gcc -shared -Xlinker -x" - WARNINGS="$GCC_WARNINGS" - PIC="-fPIC" - DYNTYPE=so - LD=ld - LD_L="$LD -x -shared" - RANLIB=ranlib - STRIP=strip - CC_STATIC="-Xlinker -export-dynamic" - ;; - aix) - OS_CFLAGS="" - DYNTYPE=lo - LD=ld - LD_L=ld -bexpall -bM:SRE -bnoentry - LD_D="$LD_L" - RANLIB=ranlib - STRIP=strip - ;; - *) - OS_CFLAGS="" - ;; - esac -else -### -### Non-gcc needs attention on per-OS basis -### - case "$OS" in - darwin) -# add some stuff here (see sourceforge bug 534205) -# DOCDIR=/System/Documentation/Administration/Libraries/PAM -# MANDIR=/usr/share/man - ;; - solaris) - ### Support for Solaris-C - OS_CFLAGS="" - WARNINGS="" - PIC="-K pic" - LD=ld - LD_D="cc -z text -G -R." - LD_L="$LD_D" - RANLIB=ranlib - STRIP=strip - CC_STATIC= - ;; - irix*) - OSRELEASE=`uname -r` - if test "$OSRELEASE" = 6.5; then - OS_CFLAGS="" - WARNINGS="-fullwarn" - PIC= #PIC code is default for IRIX - LD="cc -shared" # modules friendly approach - LD_D="cc -shared" - LD_L="ld -G -z redlocsym" - RANLIB=echo - STRIP=strip - CC_STATIC= - else - echo "IRIX prior to 6.5 not allowed for" - exit - fi - ;; - *) echo "Native compiler on $OS is not yet supported" - exit - ;; - esac -fi - -AC_SUBST(DYNTYPE) -AC_SUBST(OS_CFLAGS) -AC_SUBST(WARNINGS) -AC_SUBST(PIC) -AC_SUBST(LD) -AC_SUBST(LD_D) -AC_SUBST(LD_L) -AC_SUBST(RANLIB) -AC_SUBST(STRIP) -AC_SUBST(CC_STATIC) - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_BIGENDIAN -AC_C_CONST -AC_TYPE_UID_T -AC_TYPE_OFF_T -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_STRUCT_TM - -dnl Checks for library functions. -AC_TYPE_GETGROUPS -AC_PROG_GCC_TRADITIONAL -AC_FUNC_MEMCMP -AC_FUNC_VPRINTF -AC_CHECK_FUNCS(gethostname gettimeofday mkdir select strcspn strdup strerror strspn strstr strtol uname) - -AC_CHECK_FUNCS(getpwnam_r getgrnam_r) - -dnl Checks for programs/utilities -AC_CHECK_PROG(HAVE_SGML2TXT, sgml2txt, yes, no) -AC_CHECK_PROG(HAVE_SGML2HTML, sgml2html, yes, no) -AC_CHECK_PROG(HAVE_SGML2LATEX, sgml2latex, yes, no) -if test $HAVE_SGML2LATEX = "yes" ; then - if sgml2latex -h | grep -e --paper | grep ' -p ' > /dev/null ; then - PSER="sgml2latex -o ps" - else - PSER="sgml2latex -p" - fi - AC_CHECK_PROG(HAVE_PS2PDF, ps2pdf, yes, no) -else - AC_CHECK_PROG(HAVE_SGML2PS, sgml2ps, yes, no) - if test $HAVE_SGML2PS = yes ; then - PSER="sgml2ps" - fi -fi -AC_SUBST(PSER) -AC_SUBST(PS2PDF) - -dnl Files to be created from when we run configure -AC_OUTPUT(Make.Rules) diff --git a/defs/debian.defs b/defs/debian.defs deleted file mode 100644 index 19ba4663..00000000 --- a/defs/debian.defs +++ /dev/null @@ -1,40 +0,0 @@ -## -# defs for Debian -# Ben Collins <bcollins@debian.org> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -## - -CFLAGS := -O2 -I${shell pwd}/include # -D__NO_STRING_INLINES -ifneq (,$(findstring $(DEB_BUILD_OPTIONS),debug DEBUG Debug)) - CFLAGS += -g -endif - -OS := $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM) -ARCH := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) -CC := gcc -INSTALL := install -MKDIR := mkdir -p -ULIBS := -LD := ld -LD_D := gcc -shared -Xlinker -x -LD_L := $(LD) -x -shared -AR := ar -cr -RANLIB := ranlib -PREFIX := -LIBDIR := $(PREFIX)/lib -USESONAME := yes -SOSWITCH := -soname -LINKLIBS := -lc -L${shell pwd}/libpam -L${shell pwd}/libpam_misc -NEEDSONAME := no -LDCONFIG := /sbin/ldconfig -FAKEROOT := -SUPLEMENTED := $(PREFIX)/sbin -SECUREDIR := $(LIBDIR)/security -INCLUDED := /usr/include/security -CONFIGED := /etc -SCONFIGED := /etc/security -EXTRALS := -lnsl -lcrypt -WARNINGS := -Wall diff --git a/defs/hpux.defs b/defs/hpux.defs deleted file mode 100644 index d8341983..00000000 --- a/defs/hpux.defs +++ /dev/null @@ -1,36 +0,0 @@ -## -# HPUX defs contributed by Derrick J Brashear <shadow@dementia.org> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the default version. Please look in .../defs/ for your -# preferred OS/vendor. - -OS=hpux9 -ARCH=hpux -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=-g -DPAM_SHL -DHAVE_UTMP_H -ULIBS= -LD=ld -LD_D=$(LD) -b -LD_L=$(LD) -b -USESONAME=no -NEEDSONAME=no -LDCONFIG=: -AR=ar -cr -RANLIB=ranlib -FAKEROOT= -PREFIX=/usr -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security -DYNLOAD="dld" -DYNTYPE="sl" -SHLIBMODE=755 diff --git a/defs/linux.defs b/defs/linux.defs deleted file mode 100644 index 0e274320..00000000 --- a/defs/linux.defs +++ /dev/null @@ -1,32 +0,0 @@ -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the default version. Please look in .../defs/ for your -# preferred OS/vendor. - -OS=linux -ARCH=i386 # should be changed for alpha -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=-O7 -pipe -g -ULIBS=#-lefence -LD=ld -LD_D=gcc -shared -Xlinker -x -LD_L=$(LD) -x -shared -USESONAME=yes -LINKLIBS=-lc -SOSWITCH=-soname -NEEDSONAME=no -LDCONFIG=/sbin/ldconfig -AR=ar -cr -RANLIB=ranlib -FAKEROOT= -PREFIX=/usr -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security diff --git a/defs/morgan.defs b/defs/morgan.defs deleted file mode 100644 index 2b0cf289..00000000 --- a/defs/morgan.defs +++ /dev/null @@ -1,36 +0,0 @@ -## -# defs for Andrew's debugging version (which is a modified Red Hat -# box) -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the version used for Red Hat Linux. - -OS=linux -ARCH=i386 -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=$(RPM_OPT_FLAGS) -pipe -g -ULIBS= -#-lefence -LD=ld -LD_D=gcc -shared -Xlinker -x -LD_L=$(LD) -x -shared -USESONAME=yes -SOSWITCH=-soname -LINKLIBS=-lc -NEEDSONAME=no -LDCONFIG=/sbin/ldconfig -AR=ar -cr -RANLIB=ranlib -FAKEROOT=$(RPM_BUILD_ROOT) -PREFIX= -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security.d -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security diff --git a/defs/redhat.defs b/defs/redhat.defs deleted file mode 100644 index a6ed36da..00000000 --- a/defs/redhat.defs +++ /dev/null @@ -1,36 +0,0 @@ -## -# defs for Red Hat Linux -# Michael K. Johnson <johnsonm@redhat.com> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the version used for Red Hat Linux. - -OS=linux -ARCH=$(shell rpm --showrc | grep '^build arch' | sed 's/^.*: //g') -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=$(RPM_OPT_FLAGS) -pipe -g -ULIBS=#-lefence -LD=ld -LD_D=gcc -shared -Xlinker -x -LD_L=$(LD) -x -shared -USESONAME=yes -SOSWITCH=-soname -LINKLIBS=-lc -NEEDSONAME=no -LDCONFIG=/sbin/ldconfig -AR=ar -cr -RANLIB=ranlib -FAKEROOT=$(RPM_BUILD_ROOT) -PREFIX= -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security -EXTRALS=-lcrypt diff --git a/defs/redhat4.defs b/defs/redhat4.defs deleted file mode 100644 index 219abeb6..00000000 --- a/defs/redhat4.defs +++ /dev/null @@ -1,35 +0,0 @@ -## -# defs for Red Hat Linux -# Michael K. Johnson <johnsonm@redhat.com> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the version used for Red Hat Linux. - -OS=linux -ARCH=$(shell rpm --showrc | grep '^build arch' | sed 's/^.*: //g') -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=$(RPM_OPT_FLAGS) -pipe -g -ULIBS=#-lefence -LD=ld -LD_D=gcc -shared -Xlinker -x -LD_L=$(LD) -x -shared -USESONAME=yes -SOSWITCH=-soname -LINKLIBS=-lc -NEEDSONAME=no -LDCONFIG=/sbin/ldconfig -AR=ar -cr -RANLIB=ranlib -FAKEROOT=$(RPM_BUILD_ROOT) -PREFIX= -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security diff --git a/defs/solaris-2.1.5.defs b/defs/solaris-2.1.5.defs deleted file mode 100644 index 4624b604..00000000 --- a/defs/solaris-2.1.5.defs +++ /dev/null @@ -1,45 +0,0 @@ -## -# Solaris defs contributed by Josh Wilmes <josh@makita.jpl.nasa.gov> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the default version. Please look in .../defs/ for your -# preferred OS/vendor. - -# Please note that the linker used must be the GNU ld, not the native Sun -# linker. It is fairly common for the gnu linker (/usr/ccs/bin/ld) to be -# configured as the default linker for gcc. To tell gcc to use the -# gnu linker, you need to set the GCC_EXEC_PREFIX environment variable -# to point at the directory where the gnu linker is installed. Here's -# what I do: -# $ mkdir /tmp/foo -# $ ln -s /path/to/gnu/ld /tmp/foo/ld -# $ export GCC_EXEC_PREFIX=/tmp/foo/ -# $ export PATH=/tmp/foo:$PATH - -OS=solaris -ARCH=sun -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=-O7 -pipe -g -D__EXTENSIONS__ -Dsolaris -ULIBS= -LD_D=gcc -shared -Xlinker -x -LD=ld -LD_L=$(LD) -G -USESONAME=yes -SOSWITCH=-h -NEEDSONAME=no -LDCONFIG=/sbin/echo -AR=ar -cr -RANLIB=ranlib -FAKEROOT= -PREFIX=/usr -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security diff --git a/defs/solaris.defs b/defs/solaris.defs deleted file mode 100644 index f9f26529..00000000 --- a/defs/solaris.defs +++ /dev/null @@ -1,48 +0,0 @@ -## -# Solaris defs contributed by Josh Wilmes <josh@makita.jpl.nasa.gov> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the default version. Please look in .../defs/ for your -# preferred OS/vendor. - -# Please note that the linker used must be the GNU ld, not the native Sun -# linker. It is fairly common for the gnu linker (/usr/ccs/bin/ld) to be -# configured as the default linker for gcc. To tell gcc to use the -# gnu linker, you need to set the GCC_EXEC_PREFIX environment variable -# to point at the directory where the gnu linker is installed. Here's -# what I do: -# $ mkdir /tmp/foo -# $ ln -s /path/to/gnu/ld /tmp/foo/ld -# $ export GCC_EXEC_PREFIX=/tmp/foo/ -# $ export PATH=/tmp/foo:$PATH - -OS=solaris -ARCH=sun -CC=cc -INSTALL=install -MKDIR=mkdir -p -WARNINGS = -D_POSIX_SOURCE -PIC=-KPIC -CFLAGS=-g -D__EXTENSIONS__ -Dsolaris -ULIBS= -LD=ld -LD_L=$(LD) -G -LD_D=$(LD_L) -RDYNAMIC= -USESONAME=yes -SOSWITCH=-h -NEEDSONAME=no -LDCONFIG=echo -AR=ar -cr -RANLIB=ranlib -FAKEROOT= -PREFIX=/usr -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security diff --git a/defs/sunos.defs b/defs/sunos.defs deleted file mode 100644 index 158accc5..00000000 --- a/defs/sunos.defs +++ /dev/null @@ -1,37 +0,0 @@ -## -# SunOS defs contributed by Derrick J Brashear <shadow@dementia.org> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the SunOS version. Please look in .../defs/ for your -# preferred OS/vendor. - -OS=sunos -ARCH=sun -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=-O2 -pipe -g -D__EXTENSIONS__ -ULIBS= -LD_D=gcc -shared -Xlinker -x -LD=ld -LD_L=$(LD) -USESONAME=no -NEEDSONAME=yes -LDCONFIG=/usr/etc/ldconfig -AR=ar cr -RANLIB=ranlib -FAKEROOT= -PREFIX=/usr -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security -WARNINGS= -ansi -Wall -Wwrite-strings \ - -Wpointer-arith -Wcast-qual -Wcast-align \ - -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -Wshadow diff --git a/defs/suse.defs b/defs/suse.defs deleted file mode 100644 index 1fc6b741..00000000 --- a/defs/suse.defs +++ /dev/null @@ -1,36 +0,0 @@ -## -# defs for SuSE Linux -# Thorsten Kukuk <kukuk@suse.de> -## -# this file indicates the compiler and the various hardware/OS dependent -# flags for installation. It also defines the various destinations of -# installed files on the system. -# -# This file is the version used for SuSE Linux. - -OS=linux -ARCH=$(shell rpm --showrc | grep 'build arch' | grep -v "compatible" | sed 's/^.*: //g') -CC=gcc -INSTALL=install -MKDIR=mkdir -p -CFLAGS=$(RPM_OPT_FLAGS) -pipe -D_REENTRANT -ULIBS=#-lefence -LD=ld -LD_D=gcc -shared -Xlinker -x -LD_L=$(LD) -x -shared -USESONAME=yes -SOSWITCH=-soname -LINKLIBS=-lc -NEEDSONAME=yes -LDCONFIG=/sbin/ldconfig -AR=ar -cr -RANLIB=ranlib -FAKEROOT=$(RPM_BUILD_ROOT) -PREFIX= -SUPLEMENTED=$(PREFIX)/sbin -LIBDIR=$(PREFIX)/lib -SECUREDIR=$(LIBDIR)/security -INCLUDED=/usr/include/security -CONFIGED=/etc -SCONFIGED=/etc/security -EXTRALS=-lcrypt diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100644 index 7ac74f9d..00000000 --- a/doc/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -pam.sgml -MODULES-SGML diff --git a/doc/CREDITS b/doc/CREDITS deleted file mode 100644 index df0eb599..00000000 --- a/doc/CREDITS +++ /dev/null @@ -1,49 +0,0 @@ -<!-- - an sgml list of people to credit for their contributions to Linux-PAM - $Id$ - --> -Chris Adams, -Peter Allgeyer, -Tim Baverstock, -Tim Berger, -Craig S. Bell, -Derrick J. Brashear, -Ben Buxton, -Seth Chaiklin, -Oliver Crow, -Chris Dent, -Marc Ewing, -Cristian Gafton, -Emmanuel Galanos, -Brad M. Garcia, -Eric Hester, -Michel D'Hooge, -Roger Hu, -Eric Jacksch, -Michael K. Johnson, -David Kinchlea, -Olaf Kirch, -Marcin Korzonek, -Stephen Langasek, -Nicolai Langfeldt, -Elliot Lee, -Luke Kenneth Casson Leighton, -Al Longyear, -Ingo Luetkebohle, -Marek Michalkiewicz, -Robert Milkowski, -Aleph One, -Martin Pool, -Sean Reifschneider, -Jan Rekorajski, -Erik Troan, -Theodore Ts'o, -Jeff Uphoff, -Myles Uyema, -Savochkin Andrey Vladimirovich, -Ronald Wahl, -David Wood, -John Wilmes, -Joseph S. D. Yao -and -Alex O. Yuriev. diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 63c11fbf..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,167 +0,0 @@ - -### $Id$ - -include ../Make.Rules - -####################################################### - -FILES=pam pam_appl pam_modules -FSRCS=pam.sgml pam_appl.sgml pam_modules.sgml - -TEXTS=txts/pam.txt txts/pam_appl.txt txts/pam_modules.txt -HTMLS=html/pam.html html/pam_appl.html html/pam_modules.html -PSFILES=ps/pam.ps ps/pam_appl.ps ps/pam_modules.ps -PDFFILES=pdf/pam.pdf ps/pam_appl.pdf ps/pam_modules.pdf - -MODULES=$(shell ls modules/*.sgml) - -####################################################### - -dummy: - @echo "Making the documentation..." - @$(MAKE) all - -# note, at this time we don't include pdf files by default, but you -# can type make pdf in this directory and see what happens in the pdf -# subdirectory. - -all: htmls texts postscript - -htmls: $(HTMLS) - -$(HTMLS) : $(FSRCS) -ifeq ($(HAVE_SGML2HTML),yes) - @for i in $(FILES) ; do \ - if [ ! -f "html/$$i.html" ] || [ "$$i.sgml" -nt "html/$$i.html" ]; \ - then \ - cd html ; sgml2html ../$$i ; \ - if [ $$? -ne 0 ]; then exit 1 ; fi ; \ - cd .. ; \ - fi ; \ - done -else - @echo XXX - you do not have the sgml2html binary installed -endif - -texts: $(TEXTS) - -$(TEXTS) : $(FSRCS) -ifeq ($(HAVE_SGML2TXT),yes) - @for i in $(FILES) ; do \ - if [ ! -f "txts/$$i.txt" ] \ - || [ "$$i.sgml" -nt "txts/$$i.txt" ]; then \ - cd txts ; sgml2txt ../$$i ; cd .. ; \ - fi ; \ - done -else - @echo XXX - you do not have the sgml2txt binary installed -endif - -postscript: $(PSFILES) - -$(PSFILES): $(FSRCS) -ifneq ($(PSER),) - @for i in $(FILES) ; do \ - if [ ! -f "ps/$$i.ps" ] || [ "$$i.sgml" -nt "ps/$$i.ps" ]; then \ - cd ps ; $(PSER) ../$$i ; cd .. ; \ - fi ; \ - done -else - @echo XXX - neither sgml2ps nor sgml2latex binaries are installed -endif - -pdf: $(PDFFILES) - -$(PDFFILES) : $(PSFILES) -ifeq ($(HAVE_PS2PDF),yes) - @for i in $(FILES) ; do \ - if [ ! -f "pdf/$$i.pdf" ] || [ "ps/$$i.ps" -nt "ps/$$i.pdf" ]; then \ - ps2pdf ps/$$i.ps pdf/$$i.pdf ; \ - fi ; \ - done -else - @echo XXX - ps2pdf is not installed -endif - -pam.sgml: pam_source.sgml MODULES-SGML CREDITS - @sed -e '/^<!\-\- insert\-file MODULES\-SGML \-\->/r MODULES-SGML' pam_source.sgml | sed -e '/^<!\-\- insert\-file CREDITS \-\->/r CREDITS' > pam.sgml - -MODULES-SGML: $(MODULES) - @echo 'Building module text from files in modules/*.sgml' - @rm -f MODULES-SGML - @echo '<!-- modules included:' > MODULES-SGML - @ls modules/*.sgml >> MODULES-SGML - @echo ' and that is all -->' >> MODULES-SGML - @cat modules/*.sgml >> MODULES-SGML - -extraclean: clean - -remove: - cd man && for file in *.3 ; do \ - rm -f $(FAKEROOT)$(MANDIR)/man3/$$file ; \ - done - cd man && for file in *.8 ; do \ - rm -f $(FAKEROOT)$(MANDIR)/man8/$$file ; \ - done - cd txts && for file in *.txt; do \ - rm -f $(FAKEROOT)$(DOCDIR)/text/$$file ; \ - done - cd ps && for file in *.ps; do \ - rm -f $(FAKEROOT)$(DOCDIR)/ps/$$file ; \ - done - cd html && for file in *.html; do \ - rm -f $(FAKEROOT)$(DOCDIR)/html/$$file ; \ - done - -install: all -ifeq ($(HAVE_SGML2TXT),yes) - mkdir -p $(FAKEROOT)$(DOCDIR)/text - for file in txts/*.txt; do \ - install -m 644 $$file $(FAKEROOT)$(DOCDIR)/text ; \ - done -endif -ifneq ($(PSER),) - mkdir -p $(FAKEROOT)$(DOCDIR)/ps - for file in ps/*.ps; do \ - install -m 644 $$file $(FAKEROOT)$(DOCDIR)/ps ; \ - done - ifeq ($(HAVE_PS2PDF),yes) - mkdir -p $(FAKEROOT)$(DOCDIR)/pdf - for file in pdf/*.pdf; do \ - install -m 644 $$file $(FAKEROOT)$(DOCDIR)/pdf ; \ - done - endif -endif -ifeq ($(HAVE_SGML2HTML),yes) - mkdir -p $(FAKEROOT)$(DOCDIR)/html - for file in html/*.html; do \ - install -m 644 $$file $(FAKEROOT)$(DOCDIR)/html ; \ - done -endif - mkdir -p $(FAKEROOT)$(MANDIR)/man3 - mkdir -p $(FAKEROOT)$(MANDIR)/man8 - for file in man/*.3 ; do \ - install -m 644 $$file $(FAKEROOT)$(MANDIR)/man3 ; \ - done - for file in man/*.8 ; do \ - install -m 644 $$file $(FAKEROOT)$(MANDIR)/man8 ; \ - done - -spec: specs/draft-morgan-pam.raw - cd specs/formatter && $(MAKE) - specs/formatter/padout < specs/draft-morgan-pam.raw > specs/draft-morgan-pam-current.txt - -releasedocs: all spec - tar zvfc Linux-PAM-$(MAJOR_REL).$(MINOR_REL)-docs.tar.gz --exclude CVS html ps txts specs/draft-morgan-pam-current.txt - -clean: - rm -f *~ *.bak - rm -f html/pam*.html - rm -f man/*~ - rm -f $(TEXTS) - rm -f $(PSFILES) ps/missfont.log - rm -f pdf/*.pdf - rm -f MODULES-SGML pam.sgml - rm -f specs/draft-morgan-pam-current.txt - $(MAKE) -C specs/formatter clean - diff --git a/doc/NOTES b/doc/NOTES deleted file mode 100644 index b0f40d47..00000000 --- a/doc/NOTES +++ /dev/null @@ -1,16 +0,0 @@ -Things to be added: - -@ modules: -@ application: - - use of - 'user' = user to become, - 'uid' = user requesting service - 'euid' = privilege of current process. - -@ sysadmin: - - included modules: - behavior - non-included modules: - behavior/pointers. diff --git a/doc/figs/pam_orient.txt b/doc/figs/pam_orient.txt deleted file mode 100644 index a8b745a1..00000000 --- a/doc/figs/pam_orient.txt +++ /dev/null @@ -1,23 +0,0 @@ - - - - +----------------+ - | application: X | - +----------------+ / +----------+ +================+ - | authentication-[---->--\--] Linux- |--<--| /etc/pam.conf | - | + [----<--/--] PAM | |================| - |[conversation()][--+ \ | | | X auth .. a.so | - +----------------+ | / +-n--n-----+ | X auth .. b.so | - | | | __| | | _____/ - | service user | A | | |____,-----' - | | | V A - +----------------+ +------|-----|---------+ -----+------+ - +---u-----u----+ | | | - | auth.... |--[ a ]--[ b ]--[ c ] - +--------------+ - | acct.... |--[ b ]--[ d ] - +--------------+ - | password |--[ b ]--[ c ] - +--------------+ - | session |--[ e ]--[ c ] - +--------------+ \ No newline at end of file diff --git a/doc/html/.cvsignore b/doc/html/.cvsignore deleted file mode 100644 index 3b358a3a..00000000 --- a/doc/html/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -pam*.html \ No newline at end of file diff --git a/doc/html/index.html b/doc/html/index.html deleted file mode 100644 index 1ffd7e38..00000000 --- a/doc/html/index.html +++ /dev/null @@ -1,21 +0,0 @@ - -<HTML> -<HEAD> -<TITLE>Linux-PAM - Pluggable Authentication Modules for Linux - - - -

-Here is the documentation for Linux-PAM. As you will see it is -currently not complete. However, in order of decreasing length: - -

- -
-

-REVISION: $Id$ - diff --git a/doc/man/pam.8 b/doc/man/pam.8 deleted file mode 100644 index 939a0fe9..00000000 --- a/doc/man/pam.8 +++ /dev/null @@ -1,369 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996-7,2001 -.TH PAM 8 "2001 Jan 20" "Linux-PAM 0.74" "Linux-PAM Manual" -.SH NAME - -Linux-PAM \- Pluggable Authentication Modules for Linux - -.SH SYNOPSIS -.B /etc/pam.conf -.sp 2 -.SH DESCRIPTION - -This manual is intended to offer a quick introduction to -.BR Linux-PAM ". " -For more information the reader is directed to the -.BR "Linux-PAM system administrators' guide". - -.sp -.BR Linux-PAM -Is a system of libraries that handle the authentication tasks of -applications (services) on the system. The library provides a stable -general interface (Application Programming Interface - API) that -privilege granting programs (such as -.BR login "(1) " -and -.BR su "(1)) " -defer to to perform standard authentication tasks. - -.sp -The principal feature of the PAM approach is that the nature of the -authentication is dynamically configurable. In other words, the -system administrator is free to choose how individual -service-providing applications will authenticate users. This dynamic -configuration is set by the contents of the single -.BR Linux-PAM -configuration file -.BR /etc/pam.conf "." -Alternatively, the configuration can be set by individual -configuration files located in the -.B /etc/pam.d/ -directory. -.IB "The presence of this directory will cause " Linux-PAM " to ignore" -.BI /etc/pam.conf "." - -.sp -From the point of view of the system administrator, for whom this -manual is provided, it is not of primary importance to understand the -internal behavior of the -.BR Linux-PAM -library. The important point to recognize is that the configuration -file(s) -.I define -the connection between applications -.BR "" "(" services ")" -and the pluggable authentication modules -.BR "" "(" PAM "s)" -that perform the actual authentication tasks. - -.sp -.BR Linux-PAM -separates the tasks of -.I authentication -into four independent management groups: -.BR "account" " management; " -.BR "auth" "entication management; " -.BR "password" " management; " -and -.BR "session" " management." -(We highlight the abbreviations used for these groups in the -configuration file.) - -.sp -Simply put, these groups take care of different aspects of a typical -user's request for a restricted service: - -.sp -.BR account " - " -provide account verification types of service: has the user's password -expired?; is this user permitted access to the requested service? - -.br -.BR auth "entication - " -establish the user is who they claim to be. Typically this is via some -challenge-response request that the user must satisfy: if you are who -you claim to be please enter your password. Not all authentications -are of this type, there exist hardware based authentication schemes -(such as the use of smart-cards and biometric devices), with suitable -modules, these may be substituted seamlessly for more standard -approaches to authentication - such is the flexibility of -.BR Linux-PAM "." - -.br -.BR password " - " -this group's responsibility is the task of updating authentication -mechanisms. Typically, such services are strongly coupled to those of -the -.BR auth -group. Some authentication mechanisms lend themselves well to being -updated with such a function. Standard UN*X password-based access is -the obvious example: please enter a replacement password. - -.br -.BR session " - " -this group of tasks cover things that should be done prior to a -service being given and after it is withdrawn. Such tasks include the -maintenance of audit trails and the mounting of the user's home -directory. The -.BR session -management group is important as it provides both an opening and -closing hook for modules to affect the services available to a user. - -.SH The configuration file(s) - -When a -.BR Linux-PAM -aware privilege granting application is started, it activates its -attachment to the PAM-API. This activation performs a number of -tasks, the most important being the reading of the configuration file(s): -.BR /etc/pam.conf "." -Alternatively, this may be the contents of the -.BR /etc/pam.d/ -directory. - -These files list the -.BR PAM "s" -that will do the authentication tasks required by this service, and -the appropriate behavior of the PAM-API in the event that individual -.BR PAM "s " -fail. - -.sp -The syntax of the -.B /etc/pam.conf -configuration file is as follows. The file is made -up of a list of rules, each rule is typically placed on a single line, -but may be extended with an escaped end of line: `\\'. Comments -are preceded with `#' marks and extend to the next end of line. - -.sp -The format of each rule is a space separated collection of tokens, the -first three being case-insensitive: - -.sp -.br -.BR " service type control module-path module-arguments" - -.sp -The syntax of files contained in the -.B /etc/pam.d/ -directory, are identical except for the absence of any -.I service -field. In this case, the -.I service -is the name of the file in the -.B /etc/pam.d/ -directory. This filename must be in lower case. - -.sp -An important feature of -.BR Linux-PAM ", " -is that a number of rules may be -.I stacked -to combine the services of a number of PAMs for a given authentication -task. - -.sp -The -.BR service -is typically the familiar name of the corresponding application: -.BR login -and -.BR su -are good examples. The -.BR service "-name, " other ", " -is reserved for giving -.I default -rules. Only lines that mention the current service (or in the absence -of such, the -.BR other -entries) will be associated with the given service-application. - -.sp -The -.BR type -is the management group that the rule corresponds to. It is used to -specify which of the management groups the subsequent module is to -be associated with. Valid entries are: -.BR account "; " -.BR auth "; " -.BR password "; " -and -.BR session "." -The meaning of each of these tokens was explained above. - -.sp -The third field, -.BR control ", " -indicates the behavior of the PAM-API should the module fail to -succeed in its authentication task. There are two types of syntax for -this control field: the simple one has a single simple keyword; the -more complicated one involves a square-bracketed selection of -.B value=action -pairs. - -.sp -For the simple (historical) syntax valid -.BR control -values are: -.BR requisite -- failure of such a PAM results in the immediate termination of the -authentication process; -.BR required -- failure of such a PAM will ultimately lead to the PAM-API returning -failure but only after the remaining -.I stacked -modules (for this -.BR service -and -.BR type ")" -have been invoked; -.BR sufficient -- success of such a module is enough to satisfy the authentication -requirements of the stack of modules (if a prior -.BR required -module has failed the success of this one is -.IR ignored "); " -.BR optional -- the success or failure of this module is only important if it is the -only module in the stack associated with this -.BR service "+" type "." - -.sp -For the more complicated syntax valid -.B control -values have the following form: -.sp -.RB [value1=action1 value2=action2 ...] -.sp -Where -.B valueN -corresponds to the return code from the function invoked in the module -for which the line is defined. It is selected from one of these: -.BR success ; -.BR open_err ; -.BR symbol_err ; -.BR service_err ; -.BR system_err ; -.BR buf_err ; -.BR perm_denied ; -.BR auth_err ; -.BR cred_insufficient ; -.BR authinfo_unavail ; -.BR user_unknown ; -.BR maxtries ; -.BR new_authtok_reqd ; -.BR acct_expired ; -.BR session_err ; -.BR cred_unavail ; -.BR cred_expired ; -.BR cred_err ; -.BR no_module_data ; -.BR conv_err ; -.BR authtok_err ; -.BR authtok_recover_err ; -.BR authtok_lock_busy ; -.BR authtok_disable_aging ; -.BR try_again ; -.BR ignore ; -.BR abort ; -.BR authtok_expired ; -.BR module_unknown ; -.BR bad_item "; and" -.BR default . -The last of these, -.BR default , -implies 'all -.BR valueN 's -not mentioned explicitly. Note, the full list of PAM errors is -available in /usr/include/security/_pam_types.h . The -.B actionN -can be: an unsigned integer, -.BR J , -signifying an action of 'jump over the next J modules in the stack'; -or take one of the following forms: -.br -.B ignore -- when used with a stack of modules, the module's return status will -not contribute to the return code the application obtains; -.br -.B bad -- this action indicates that the return code should be thought of as -indicative of the module failing. If this module is the first in the -stack to fail, its status value will be used for that of the whole -stack. -.br -.B die -- equivalent to bad with the side effect of terminating the module -stack and PAM immediately returning to the application. -.br -.B ok -- this tells PAM that the administrator thinks this return code -should contribute directly to the return code of the full stack of -modules. In other words, if the former state of the stack would lead -to a return of -.BR PAM_SUCCESS , -the module's return code will override this value. Note, if the former -state of the stack holds some value that is indicative of a modules -failure, this 'ok' value will not be used to override that value. -.br -.B done -- equivalent to ok with the side effect of terminating the module -stack and PAM immediately returning to the application. -.br -.B reset -- clear all memory of the state of the module stack and start again -with the next stacked module. - -.sp -.BR module-path -- this is either the full filename of the PAM to be used by the -application (it begins with a '/'), or a relative pathname from the -default module location: -.BR /lib/security/ . - -.sp -.BR module-arguments -- these are a space separated list of tokens that can be used to -modify the specific behavior of the given PAM. Such arguments will be -documented for each individual module. - -.SH "FILES" -.BR /etc/pam.conf " - the configuration file" -.br -.BR /etc/pam.d/ " - the" -.BR Linux-PAM -configuration directory. Generally, if this directory is present, the -.B /etc/pam.conf -file is ignored. -.br -.BR /lib/libpam.so.X " - the dynamic library" -.br -.BR /lib/security/*.so " - the PAMs - -.SH ERRORS -Typically errors generated by the -.BR Linux-PAM -system of libraries, will be written to -.BR syslog "(3)." - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. -.br -Contains additional features, but remains backwardly compatible with -this RFC. - -.SH BUGS -.sp 2 -None known. - -.SH "SEE ALSO" - -The three -.BR Linux-PAM -Guides, for -.BR "system administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam.conf.8 b/doc/man/pam.conf.8 deleted file mode 100644 index d067b559..00000000 --- a/doc/man/pam.conf.8 +++ /dev/null @@ -1 +0,0 @@ -.so pam.8 diff --git a/doc/man/pam.d.8 b/doc/man/pam.d.8 deleted file mode 100644 index d067b559..00000000 --- a/doc/man/pam.d.8 +++ /dev/null @@ -1 +0,0 @@ -.so pam.8 diff --git a/doc/man/pam_authenticate.3 b/doc/man/pam_authenticate.3 deleted file mode 100644 index ba1bc52e..00000000 --- a/doc/man/pam_authenticate.3 +++ /dev/null @@ -1,91 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996-7 -.TH PAM_AUTHENTICATE 3 "1996 Dec 9" "Linux-PAM 0.55" "App. Programmers' Manual" -.SH NAME - -pam_authenticate \- authenticate a user - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_authenticate(pam_handle_t " *pamh ", int " flags ");" -.sp 2 -.SH DESCRIPTION -.B pam_authenticate - -.br -Use this function to authenticate an applicant user. It is linked -.I dynamically -to the authentication modules by -.BR Linux-PAM ". " -It is the task of these module to perform such an authentication. The -specific nature of the authentication is not the concern of the -application. - -.br -Following successful completion, the -.BR name -of the authenticated user will be present in the -.BR Linux-PAM -item -.BR PAM_USER ". " -This item may be recovered with a call to -.BR pam_get_item "(3)." - -.br -The application developer should note that the modules may request -that the user enter their username via the conversation mechanism (see -.BR pam_start "(3))." -Should this be the case, the user-prompt string can be set via -the -.BR PAM_USER_PROMPT -item (see -.BR pam_set_item "(3))." - -.SH "RETURN VALUE" -On success -.BR PAM_SUCCESS -is returned. All other returns should be considered -authentication failures and will be -.I delayed -by an amount specified with prior calls to -.BR pam_fail_delay "(3). " -Specific failures that demand special attention are the following: -.TP -.B PAM_ABORT -the application should exit immediately. Of course, -.BR pam_end "(3)" -should be called first. - -.TP -.B PAM_MAXTRIES -the application has tried too many times to authenticate the -user, authentication should not be attempted again. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_start "(3), " -.BR pam_get_item "(3) " -.BR pam_fail_delay "(3) " -and -.BR pam_strerror "(3). " - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_chauthtok.3 b/doc/man/pam_chauthtok.3 deleted file mode 100644 index 63904da3..00000000 --- a/doc/man/pam_chauthtok.3 +++ /dev/null @@ -1,101 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1997 -.TH PAM_CHAUTHTOK 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual" -.SH NAME - -pam_chauthtok \- updating authentication tokens - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_chauthtok(pam_handle_t " *pamh ", int " flags ");" -.sp 2 -.SH DESCRIPTION -.B pam_chauthtok - -.br -Use this function to rejuvenate the authentication tokens (passwords -etc.) of an applicant user. - -.br -Note, the application should not pre-authenticate the user, as this is -performed (if required) by the -.BR Linux-PAM -framework. - -.br -The -.I flags -argument can -.I optionally -take the value, -.BR PAM_CHANGE_EXPIRED_AUTHTOK "." -In such cases the framework is only required to update those -authentication tokens that have expired. Without this argument, the -framework will attempt to obtain new tokens for all configured -authentication mechanisms. The details of the types and number of such -schemes should not concern the calling application. - -.SH RETURN VALUE -A successful return from this function will be indicated with -.BR PAM_SUCCESS "." - -.br -Specific errors of special interest when calling this function are - -.br -.BR PAM_AUTHTOK_ERROR -- a valid new token was not obtained - -.br -.BR PAM_AUTHTOK_RECOVERY_ERR -- old authentication token was not available - -.br -.BR PAM_AUTHTOK_LOCK_BUSY -- a resource needed to update the token was locked (try again later) - -.br -.BR PAM_AUTHTOK_DISABLE_AGING -- one or more of the authentication modules does not honor -authentication token aging - -.br -.BR PAM_TRY_AGAIN -- one or more authentication mechanism is not prepared to update a -token at this time - -.br -In general other return values may be returned. They should be treated -as indicating failure. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_start "(3), " -.BR pam_authenticate "(3), " -.BR pam_setcred "(3), " -.BR pam_get_item "(3), " -.BR pam_strerror "(3) " -and -.BR pam "(8)." - -.br -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_close_session.3 b/doc/man/pam_close_session.3 deleted file mode 100644 index d851700c..00000000 --- a/doc/man/pam_close_session.3 +++ /dev/null @@ -1 +0,0 @@ -.so pam_open_session.3 diff --git a/doc/man/pam_end.3 b/doc/man/pam_end.3 deleted file mode 100644 index de999f24..00000000 --- a/doc/man/pam_end.3 +++ /dev/null @@ -1 +0,0 @@ -.so pam_start.3 diff --git a/doc/man/pam_fail_delay.3 b/doc/man/pam_fail_delay.3 deleted file mode 100644 index f6cd238a..00000000 --- a/doc/man/pam_fail_delay.3 +++ /dev/null @@ -1,130 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1997 -.TH PAM_FAIL_DELAY 3 "1997 Jan 12" "Linux-PAM 0.56" "Programmers' Manual" -.SH NAME - -pam_fail_delay \- request a delay on failure - -.SH SYNOPSIS -.B #include -.br -or, -.br -.B #include -.sp -.BI "int pam_fail_delay(pam_handle_t " "*pamh" ", unsigned int " "usec" ");" -.sp 2 -.SH DESCRIPTION -.br -It is often possible to attack an authentication scheme by exploiting -the time it takes the scheme to deny access to an applicant user. In -cases of -.I short -timeouts, it may prove possible to attempt a -.I brute force -dictionary attack -- with an automated process, the attacker tries all -possible passwords to gain access to the system. In other cases, -where individual failures can take measurable amounts of time -(indicating the nature of the failure), an attacker can obtain useful -information about the authentication process. These latter attacks -make use of procedural delays that constitute a -.I covert channel -of useful information. - -.br -To minimize the effectiveness of such attacks, it is desirable to -introduce a random delay in a failed authentication process. -.B Linux-PAM -provides such a facility. The delay occurs upon failure of the -.BR pam_authenticate "(3) " -and -.BR pam_chauthtok "(3) " -functions. It occurs -.I after -all authentication modules have been called, but -.I before -control is returned to the service application. - -.br -The function, -.BR pam_fail_delay "(3)," -is used to specify a required minimum for the length of the -failure-delay; the -.I usec -argument. This function can be called by the service application -and/or the authentication modules, both may have an interest in -delaying a reapplication for service by the user. The length of the -delay is computed at the time it is required. Its length is -pseudo-gausianly distributed about the -.I maximum -requested value; the resultant delay will differ by as much as 25% of -this maximum requested value (both up and down). - -.br -On return from -.BR pam_authenticate "(3) or " pam_chauthtok "(3)," -independent of success or failure, the new requested delay is reset to -its default value: zero. - -.SH EXAMPLE -.br -For example, a -.B login -application may require a failure delay of roughly 3 seconds. It will -contain the following code: -.sp -.br -.B " pam_fail_delay(pamh, 3000000 /* micro-seconds */ );" -.br -.B " pam_authenticate(pamh, 0);" -.sp -.br -if the modules do not request a delay, the failure delay will be -between 2.25 and 3.75 seconds. - -.br -However, the modules, invoked in the authentication process, may -also request delays: -.sp -.br -.RB " (module #1) " "pam_fail_delay(pamh, 2000000);" -.sp -.br -.RB " (module #2) " "pam_fail_delay(pamh, 4000000);" -.sp -.br -in this case, it is the largest requested value that is used to -compute the actual failed delay: here between 3 and 5 seconds. - -.SH "RETURN VALUE" -Following a successful call to -.BR pam_fail_delay "(3), " PAM_SUCCESS -is returned. All other returns should be considered serious failures. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -Under consideration by the X/Open group for future inclusion in the -PAM RFC. 1996/1/10 - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_start "(3), " -.BR pam_get_item "(3) " -and -.BR pam_strerror "(3). " - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_get_item.3 b/doc/man/pam_get_item.3 deleted file mode 100644 index f4f0d462..00000000 --- a/doc/man/pam_get_item.3 +++ /dev/null @@ -1 +0,0 @@ -.so pam_set_item.3 diff --git a/doc/man/pam_open_session.3 b/doc/man/pam_open_session.3 deleted file mode 100644 index 4e63b5c4..00000000 --- a/doc/man/pam_open_session.3 +++ /dev/null @@ -1,99 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1997 -.TH PAM_OPEN_SESSION 3 "1997 Jan 4" "Linux-PAM 0.55" "App. Programmers' Manual" -.SH NAME - -pam_open/close_session \- PAM session management - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_open_session(pam_handle_t " *pamh ", int " flags ");" -.sp -.BI "int pam_close_session(pam_handle_t " *pamh ", int " flags ");" -.sp 2 -.SH DESCRIPTION - -PAM provides management-hooks for the initialization and termination -of a session. - -.TP -.B pam_open_session -.br -Use this function to signal that an authenticated user session has -begun. It should be called only after the user is properly identified -and (where necessary) has been granted their credentials with -.BR pam_authenticate "(3)" -and -.BR pam_setcred "(3)" -respectively. - -.br -Some types of functions associated with session -initialization are logging for the purposes of system-audit and -mounting directories (the user's home directory for example). These -should not concern the application. It should be noted that the -.I effective -uid, -.BR geteuid "(2)," -of the application should be of sufficient privilege to perform such -tasks. - -.TP -.B pam_close_session -.br -Use this function to signal that a user session has -terminated. In general this function may not need to be located in the -same application as the initialization function, -.BR pam_open_session "." - -.br -Typically, this function will undo the actions of -.BR pam_open_session "." -That is, log audit information concerning the end of the user session -or unmount the user's home directory. Apart from having sufficient -privilege the details of the session termination should not concern -the calling application. It is good programming practice, however, to -cease acting on behalf of the user on returning from this call. - -.SH RETURN VALUE -A successful return from the session management functions will be -indicated with -.BR PAM_SUCCESS "." - -.br -The specific error indicating a failure to open or close a session is -.BR PAM_SESSION_ERR "." -In general other return values may be returned. They should be treated -as indicating failure. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -OSF-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_start "(3), " -.BR pam_authenticate "(3), " -.BR pam_setcred "(3), " -.BR pam_get_item "(3), " -.BR pam_strerror "(3) " -and -.BR pam "(3)." - -.br -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_set_item.3 b/doc/man/pam_set_item.3 deleted file mode 100644 index b0582778..00000000 --- a/doc/man/pam_set_item.3 +++ /dev/null @@ -1,55 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996,1997 -.TH PAM_SET_ITEM 3 "2001 Jan 21" "Linux-PAM" "App. Programmers' Manual" -.SH NAME - -pam_set_item, pam_get_item \- item manipulation under PAM - -.SH SYNOPSIS -.B #include -.br -or -.br -.B #include -.sp -.BI "int pam_set_item(pam_handle_t " *pamh ", int " item_type ", void " *item ");" -.sp -.BI "int pam_get_item(const pam_handle_t " *pamh ", int " item_type ", const void " **item_p ");" -.sp 2 -.SH DESCRIPTION -.B pam_set_item -.sp -.B pam_set_item - -These functions are currently undocumented in a man page, but see the -end of this man page for more information (the PAM guides). - -On success -.BR PAM_SUCCESS -is returned, all other return values should be treated as errors. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam (8) -and -.BR pam_strerror "(3)." - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_setcred.3 b/doc/man/pam_setcred.3 deleted file mode 100644 index 8c00fe71..00000000 --- a/doc/man/pam_setcred.3 +++ /dev/null @@ -1,79 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996,1997 -.TH PAM_SETCRED 3 "1997 July 6" "Linux-PAM 0.58" "App. Programmers' Manual" -.SH NAME - -pam_setcred \- set the credentials for the user - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_setcred(pam_handle_t " *pamh ", int " flags ");" -.sp 2 -.SH DESCRIPTION -.B pam_setcred - -This function is used to establish, maintain and delete the -credentials of a user. It should be called after a user has been -authenticated and before a session is opened for the user (with -.BR pam_open_session "(3))." - -It should be noted that credentials come in many forms. Examples -include: group memberships; ticket-files; and Linux-PAM environment -variables. For this reason, it is important that the basic identity -of the user is established, by the application, prior to a call to -this function. For example, the default -.BR Linux-PAM -environment variables should be set and also -.BR initgroups "(2) " -(or equivalent) should have been performed. - -.SH "VALID FLAGS" -.TP -.BR PAM_ESTABLISH_CRED -initialize the credentials for the user. - -.TP -.BR PAM_DELETE_CRED -delete the user's credentials. - -.TP -.BR PAM_REINITIALIZE_CRED -delete and then initialize the user's credentials. - -.TP -.BR PAM_REFRESH_CRED -extend the lifetime of the existing credentials. - -.SH "RETURN VALUE" - -On success -.BR PAM_SUCCESS -is returned, all other return values should be treated as errors. - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_authenticate "(3), " -.BR pam_strerror "(3)" -and -.BR pam_open_session "(3). " - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_start.3 b/doc/man/pam_start.3 deleted file mode 100644 index 9c11fd73..00000000 --- a/doc/man/pam_start.3 +++ /dev/null @@ -1,98 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996-7 -.TH PAM_START 3 "1997 Feb 15" "Linux-PAM 0.56" "Application Programmers' Manual" -.SH NAME - -pam_start, pam_end \- activating Linux-PAM - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_start(const char " *service ", const char " *user ", const struct pam_conv " *conv ", pam_handle_t " **pamh_p ");" -.sp -.BI "int pam_end(pam_handle_t " *pamh ", int " pam_status ");" -.sp 2 -.SH DESCRIPTION -.TP -.B pam_start -Initialize the -.I Linux-PAM -library. Identifying the application with a particular -.IR service -name. The -.IR user "name" -can take the value -.IR NULL ", " -if not known at the time the interface is initialized. The -conversation structure is passed to the library via the -.IR conv -argument. (For a complete description of this and other structures -the reader is directed to the more verbose -.IR Linux-PAM -application developers' guide). Upon successful initialization, an -opaque pointer-handle for future access to the library is returned -through the contents of the -.IR pamh_p -pointer. - -.TP -.B pam_end -Terminate the -.B Linux-PAM -library. The service application associated with the -.IR pamh -handle, is terminated. The argument, -.IR pam_status ", " -passes the value most recently returned to the application from the -library; it indicates the manner in which the library should be -shutdown. Besides carrying a return value, this argument may be -logically OR'd with -.IR PAM_DATA_SILENT -to indicate that the module should not treat the call too -seriously. It is generally used to indicate that the current closing -of the library is in a -.IR fork "(2)ed" -process, and that the parent will take care of cleaning up things that -exist outside of the current process space (files etc.). - -.SH "RETURN VALUE" -.TP -.B pam_start -.TP -.B pam_end -On success, -.BR PAM_SUCCESS -is returned - -.SH ERRORS -May be translated to text with -.BR pam_strerror "(3). " - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. -.sp -Note, the -.BR PAM_DATA_SILENT -flag is pending acceptance with the DCE (as of 1996/12/4). - -.SH BUGS -.sp 2 -None known. - -.SH "SEE ALSO" - -.BR fork "(2), " -.BR pam_authenticate "(3), " -.BR pam_acct_mgmt "(3), " -.BR pam_open_session "(3), " -and -.BR pam_chauthtok "(3)." - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/pam_strerror.3 b/doc/man/pam_strerror.3 deleted file mode 100644 index 01ee0635..00000000 --- a/doc/man/pam_strerror.3 +++ /dev/null @@ -1,51 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" ripped off from Rick Faith's getgroups man page -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1996-7 -.TH PAM_STRERROR 3 "1999 Oct 4" "Linux-PAM 0.70" "Programmers' Manual" -.SH NAME - -pam_strerror \- return a textual description of a Linux-PAM error - -.SH SYNOPSIS -.B #include -.br -or, -.br -.B #include -.sp -.BI "const char * pam_strerror( pam_handle_t " "*pamh" ", int " pam_error ");" -.sp 2 -.SH DESCRIPTION -.B pam_strerror - -This function returns some text describing the -.BR Linux-PAM -error associated with the -.B pam_error -argument. - -.SH "RETURN VALUE" - -On success this function returns a description of the indicated -error. Should the function not recognize the error, ``Unknown -Linux-PAM error'' is returned. - -.SH "CONFORMING TO" -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -This function should be internationalized. - -.SH "SEE ALSO" - -.BR pam "(8). " - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/man/template-man b/doc/man/template-man deleted file mode 100644 index b8159eb6..00000000 --- a/doc/man/template-man +++ /dev/null @@ -1,52 +0,0 @@ -.\" Hey Emacs! This file is -*- nroff -*- source. -.\" $Id$ -.\" Copyright (c) Andrew G. Morgan 1997 -.TH PAM_???? 2 "1997 Jan 4" "Linux-PAM 0.55" "Application Programmers' Manual" -.SH NAME - -function names \- brief summary of function - -.SH SYNOPSIS -.B #include -.sp -.BI "int pam_???(pam_handle_t " pamh ", int " flags); -.sp 2 -.SH DESCRIPTION -.TP -.B pam_??? -Here goes the -.I explanation -it may be quite -.IR long . -.TP -.SH "RETURN VALUE" -.B pam_??? -On success... -.BR PAM_SUCCESS -is returned -.TP -.SH ERRORS -May be translated to text with -.BR pam_strerror "(2). " - -.SH "CONFORMING TO" -.B pam_??? -DCE-RFC 86.0, October 1995. - -.SH BUGS -.sp 2 -none known. - -.SH "SEE ALSO" - -.BR pam_??? "(2), " -and -.BR pam_??? "(2). " - -Also, see the three -.BR Linux-PAM -Guides, for -.BR "System administrators" ", " -.BR "module developers" ", " -and -.BR "application developers" ". " diff --git a/doc/modules/README b/doc/modules/README deleted file mode 100644 index 448aefc7..00000000 --- a/doc/modules/README +++ /dev/null @@ -1,13 +0,0 @@ -$Id$ - -This directory contains a number of sgml sub-files. One for each -documented module. They contain a description of each module and give -some indication of its reliability. - -Additionally, there is a 'module.sgml-template' file which should be -used as a blank form for new module descriptions. - -Please feel free to submit amendments/comments etc. regarding these -files to: - - Andrew G. Morgan diff --git a/doc/modules/module.sgml-template b/doc/modules/module.sgml-template deleted file mode 100644 index 16a93c79..00000000 --- a/doc/modules/module.sgml-template +++ /dev/null @@ -1,170 +0,0 @@ - - - [*Familiar full name of module*, eg. The "allow all" module.] - -Synopsis - -

- - -Module Name: -[ - insert the name of the module - - Blank is not permitted. -] - -Author[s]: - -[ - Insert author names here - - Blank is not permitted. If in doubt, put "unknown" if the - author wishes to remain anonymous, put "anonymous". -] - -Maintainer: - -[ - Insert names and date-begun of most recent maintainer. -] - -Management groups provided: - -[ - list the subset of four management groups supported by the - module. Choose from: account; authentication; password; - session. - - Blank entries are not permitted. Explicitly list all of the - management groups. In the future more may be added to libpam! -] - -Cryptographically sensitive: - -[ - Indicate whether this module contains code that can perform - reversible (strong) encryption. This field is primarily to - ensure that people redistributing it are not unwittingly - breaking laws... - - Modules may also require the presence of some local library - that performs the necessary encryption via some standard API. - In this case "uses API" can be included in this field. The - library in question should be added to the system requirements - below. - - Blank = no cryptography is used by module. -] - -Security rating: - -[ - Initially, this field should be left blank. If someone takes - it upon themselves to test the strength of the module, it can - later be filled. - - Blank = unknown. -] - -Clean code base: - -[ - This will probably be filled by the libpam maintainer. - It can be considered to be a public humiliation list. :*) - - I am of the opinion that "gcc -with_all_those_flags" is - trying to tell us something about whether the program - works as intended. Since there is currently no Security - evaluation procedure for modules IMHO this is not a - completely unreasonable indication (a lower bound anyway) - of the reliability of a module. - - This field would indicate the number and flavor of - warnings that gcc barfs up when trying to compile the - module as part of the tree. Is this too tyrannical? - - Blank = Linux-PAM maintainer has not tested it :) -] - -System dependencies: - -[ - here we list config files, dynamic libraries needed, system - resources, kernel options.. etc. - - Blank = nothing more than libc required. -] - -Network aware: - -[ - Does the module base its behavior on probing a network - connection? Does it expect to be protected by the - application? - - Blank = Ignorance of network. -] - - - -Overview of module - -[ - some text describing the intended actions of the module - general comments mainly (specifics in sections - below). -] - -[ - - [ now we have a level subsection for each of the - management groups. Include as many as there are groups - listed above in the synopsis ] - -[ Account | Authentication | Password | Session ] component - -

- - -Recognized arguments: - -[ - List the supported arguments (leave their description for the - description below. - - Blank = no arguments are read and nothing is logged to syslog - about any arguments that are passed. Note, this - behavior is contrary to the RFC! -] - -Description: - -[ - This component of the module performs the task of ... -] - -Examples/suggested usage: - -[ - Here we list some doos and don'ts for this module. -] - - - - diff --git a/doc/modules/pam_access.sgml b/doc/modules/pam_access.sgml deleted file mode 100644 index 8a910d13..00000000 --- a/doc/modules/pam_access.sgml +++ /dev/null @@ -1,117 +0,0 @@ - - - The access module - -Synopsis - -

- - -Module Name: - -pam_access - - -Author[s]: - -Alexei Nogin <alexei@nogin.dnttm.ru> - -Maintainer: - -Management groups provided: - -account - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Requires a configuration file. By default -/etc/security/access.conf is used but this can be overridden. - -Network aware: - -Through - -Overview of module - -

-Provides logdaemon style login access control. - - Account component - -

- - -Recognized arguments: - -accessfile=/path/to/file.conf; -fieldsep=separators - -Description: - -This module provides logdaemon style login access control based on -login names and on host (or domain) names, internet addresses (or -network numbers), or on terminal line names in case of non-networked -logins. Diagnostics are reported through -The behavior of this module can be modified with the following -arguments: - - -accessfile=/path/to/file.conf - -indicate an alternative fieldsep=separators - -this option modifies the field separator character that -fieldsep=| will cause the default `:' -character to be treated as part of a field value and `|' becomes the -field separator. Doing this is useful in conjuction with a system that -wants to use pam_access with X based applications, since the - - -Examples/suggested usage: - -Use of module is recommended, for example, on administrative machines -such as /etc/pam.d style configurations where your modules live -in /lib/security, start by adding the following line to -/etc/pam.d/login, /etc/pam.d/rlogin, -/etc/pam.d/rsh and /etc/pam.d/ftp: - - - -account required /lib/security/pam_access.so - - - -Note that use of this module is not effective unless your system ignores -.rhosts files. See the the pam_rhosts_auth documentation. - -A sample access.conf configuration file is included with the -distribution. - - diff --git a/doc/modules/pam_chroot.sgml b/doc/modules/pam_chroot.sgml deleted file mode 100644 index ec739c18..00000000 --- a/doc/modules/pam_chroot.sgml +++ /dev/null @@ -1,86 +0,0 @@ - - -Chroot - -Synopsis - -

- - -Module Name: -Author: -Bruce Campbell <brucec@humbug.org.au> - -Maintainer: -Author; proposed on 20/11/96 - email for status - -Management groups provided: -account; session; authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: -Unwritten. - -System dependencies: - -Network aware: -Expects localhost. - - - -Overview of module - -

-This module is intended to provide a transparent wrapper around the -average user, one that puts them in a fake file-system (eg, their -'/' is really /some/where/else). - -

-Useful if you have several classes of users, and are slightly paranoid -about security. Can be used to limit who else users can see on the -system, and to limit the selection of programs they can run. - -Account component: - -

-Authentication component: - -

-Session component: - -

- - - -Recognized arguments: -Arguments and logging levels for the PAM version are being worked on. - -Description: - -Examples/suggested usage: -Do provide a reasonable list of programs - just tossing 'cat', 'ls', 'rm', -'cp' and 'ed' in there is a bit... -

-Don't take it to extremes (eg, you can set up a separate environment for -each user, but its a big waste of your disk space.) - - - - diff --git a/doc/modules/pam_cracklib.sgml b/doc/modules/pam_cracklib.sgml deleted file mode 100644 index 008e49f6..00000000 --- a/doc/modules/pam_cracklib.sgml +++ /dev/null @@ -1,304 +0,0 @@ - - -Cracklib pluggable password strength-checker - -Synopsis - -

- - -Module Name: - -pam_cracklib - -Author: - -Cristian Gafton <gafton@redhat.com> - -Maintainer: - -Author. - -Management groups provided: - -password - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Requires the system library /usr/lib/cracklib_dict. - -Network aware: - - - -Overview of module - -

-This module can be plugged into the -This module works in the following manner: it first calls the -Cracklib routine to check the strength of the password; if -crack likes the password, the module does an additional set of -strength checks. These checks are: - - - - -

-This module with no arguments will work well for standard unix -password encryption. With md5 encryption, passwords can be longer -than 8 characters and the default settings for this module can make it -hard for the user to choose a satisfactory new password. Notably, the -requirement that the new password contain no more than 1/2 of the -characters in the old password becomes a non-trivial constraint. For -example, an old password of the form "the quick brown fox jumped over -the lazy dogs" would be difficult to change... In addition, the -default action is to allow passwords as small as 5 characters in -length. For a md5 systems it can be a good idea to increase the -required minimum size of a password. One can then allow more credit -for different kinds of characters but accept that the new password may -share most of these characters with the old password. - -Password component - -

- - -Recognized arguments: - -Description: - -The action of this module is to prompt the user for a password and -check its strength against a system dictionary and a set of rules for -identifying poor choices. - -

-The default action is to prompt for a single password, check its -strength and then, if it is considered strong, prompt for the password -a second time (to verify that it was typed correctly on the first -occasion). All being well, the password is passed on to subsequent -modules to be installed as the new authentication token. - -

-The default action may be modified in a number of ways using the -arguments recognized by the module: - - - other, -upper, lower and Cracklib itself, a "way too short" limit of 4 which is hard -coded in and a defined limit (6) that will be checked without -reference to minlen. If you want to allow passwords as short -as 5 characters you should either not use this module or recompile -the crack library and then recompile this module. - - = 0) This is the maximum credit for having digits in the new password. If -you have less than or = 0) This is the maximum credit for having upper case letters in the new -password. If you have less than or = 0) This is the maximum credit for having lower case letters in the new -password. If you have less than or = 0) This is the maximum credit for having other characters in the new -password. If you have less than or - -Examples/suggested usage: - -

-For an example of the use of this module, we show how it may be -stacked with the password component of - -# -# These lines stack two password type modules. In this example the -# user is given 3 opportunities to enter a strong password. The -# "use_authtok" argument ensures that the pam_pwdb module does not -# prompt for a password, but instead uses the one provided by -# pam_cracklib. -# -passwd password required pam_cracklib.so retry=3 -passwd password required pam_pwdb.so use_authtok - - - -

-Another example (in the /etc/pam.d/passwd format) is for the -case that you want to use md5 password encryption: - - -#%PAM-1.0 -# -# These lines allow a md5 systems to support passwords of at least 14 -# bytes with extra credit of 2 for digits and 2 for others the new -# password must have at least three bytes that are not present in the -# old password -# -password required pam_cracklib.so \ - difok=3 minlen=15 dcredit= 2 ocredit=2 -password required pam_pwdb.so use_authtok nullok md5 - - - -

-And here is another example in case you don't want to use credits: - - -#%PAM-1.0 -# -# These lines require the user to select a password with a minimum -# length of 8 and with at least 1 digit number, 1 upper case letter, -# and 1 other character -# -password required pam_cracklib.so \ - dcredit=-1 ucredit=-1 ocredit=-1 lcredit=0 minlen=8 -password required pam_pwdb.so use_authtok nullok md5 - - - -

-In this example we simply say that the password must have a minimum -length of 8: - - -#%PAM-1.0 -# -# These lines require the user to select a password with a mimimum -# length of 8. He gets no credits and he is not forced to use -# digit numbers, upper case letters etc. -# -password required pam_cracklib.so \ - dcredit=0 ucredit=0 ocredit=0 lcredit=0 minlen=8 -password required pam_pwdb.so use_authtok nullok md5 - - - - - - diff --git a/doc/modules/pam_deny.sgml b/doc/modules/pam_deny.sgml deleted file mode 100644 index 6953231f..00000000 --- a/doc/modules/pam_deny.sgml +++ /dev/null @@ -1,177 +0,0 @@ - - -The locking-out module - -Synopsis - -

- - -Module Name: -pam_deny - -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -current Management groups provided: -account; authentication; password; session - -Cryptographically sensitive: - -Security rating: - -Clean code base: -clean. - -System dependencies: - -Network aware: - - - -Overview of module - -

-This module can be used to deny access. It always indicates a failure -to the application through the PAM framework. As is commented in the -overview section , this module -might be suitable for using for default (the Account component - -

- - -Recognized arguments: - -Description: - -This component does nothing other than return a failure. The -failure type is Examples/suggested usage: - -Stacking this module with type -The following example would make it impossible to login: - - -# -# add this line to your other login entries to disable all accounts -# -login account required pam_deny.so - - - - - -Authentication component - -

- - -Recognized arguments: - -Description: - -This component does nothing other than return a failure. The failure -type is Examples/suggested usage: - -To deny access to default applications with this component of the - - -# -# add this line to your existing OTHER entries to prevent -# authentication succeeding with default applications. -# -OTHER auth required pam_deny.so - - - - - -Password component - -

- - -Recognized arguments: - -Description: - -This component of the module denies the user the opportunity to change -their password. It always responds with Examples/suggested usage: - -This module should be used to prevent an application from updating the -applicant user's password. For example, to prevent - -# -# add this line to your other login entries to prevent the login -# application from being able to change the user's password. -# -login password required pam_deny.so - - - - - -Session component - -

- - -Recognized arguments: - -Description: - -This aspect of the module prevents an application from starting a -session on the host computer. - -Examples/suggested usage: - -Together with another session module, that displays a message of the -day perhaps ( - -# -# An example to see how to configure login to refuse the user a -# session (politely) -# -login session required pam_motd.so \ - motd=/etc/system_time -login session required pam_deny.so - - - - - - diff --git a/doc/modules/pam_env.sgml b/doc/modules/pam_env.sgml deleted file mode 100644 index d795d591..00000000 --- a/doc/modules/pam_env.sgml +++ /dev/null @@ -1,141 +0,0 @@ - - -Set/unset environment variables - -Synopsis - -

- - -Module Name: -Author: -Dave Kinchlea <kinch@kinch.ark.com> - -Maintainer: -Author - -Management groups provided: -Authentication (setcred) - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -/etc/security/pam_env.conf - -Network aware: - - - -Overview of module - -

-This module allows the (un)setting of environment variables. Supported -is the use of previously set environment variables as well as -PAM_ITEMs such as PAM_RHOST. - -Authentication component - -

- - -Recognized arguments: -Description: -This module allows you to (un)set arbitrary environment variables -using fixed strings, the value of previously set environment variables -and/or -All is controlled via a configuration file (by default, -/etc/security/pam_env.conf but can be overriden with -conffile argument). Each line starts with the variable name, -there are then two possible options for each variable DEFAULT -and OVERRIDE. DEFAULT allows an administrator to -set the value of the variable to some default value, if none is -supplied then the empty string is assumed. The OVERRIDE -option tells pam_env that it should enter in its value (overriding the -default value) if there is one to use. OVERRIDE is not used, -"" is assumed and no override will be done. - -

- - -VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] - - - -

-(Possibly non-existent) environment variables may be used in values -using the ${string} syntax and (possibly -non-existent) @{string} syntax. Both the $ -and @ characters can be backslash-escaped to be used -as literal values (as in \$. Double quotes may -be used in values (but not environment variable names) when white -space is needed the full value must be delimited by the quotes and -embedded or escaped quotes are not supported. - -

-This module can also parse a file with simple KEY=VAL pairs -on seperate lines (/etc/environment by default). You can -change the default file to parse, with the -The behavior of this module can be modified with one of the following -flags: - -

- - -/etc/security/pam_env.conf is used as -the configuration file. This option overrides the default. You must -supply a complete path + file name. - -/etc/environment is used to load KEY=VAL -pairs directly into the env. This option overrides the default. You must -supply a complete path + file name. - - - -Examples/suggested usage: - -See sample pam_env.conf for more information and examples. - - - - - - - - - - - - - - diff --git a/doc/modules/pam_filter.sgml b/doc/modules/pam_filter.sgml deleted file mode 100644 index 4d3b4e84..00000000 --- a/doc/modules/pam_filter.sgml +++ /dev/null @@ -1,150 +0,0 @@ - - -The filter module - -Synopsis - -

- - -Module Name: - -pam_filter - -Author: - -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: - -Author. - -Management groups provided: - -account; authentication; password; session - -Cryptographically sensitive: - -Not yet. - -Security rating: - -Clean code base: - -This module compiles cleanly on Linux based systems. - -System dependencies: - -To function it requires Network aware: - - - -Overview of module - -

-This module was written to offer a plug-in alternative to programs -like ttysnoop (XXX - need a reference). Since writing a filter that -performs this function has not occurred, it is currently only a toy. -The single filter provided with the module simply transposes upper and -lower case letters in the input and output streams. (This can be very -annoying and is not kind to termcap based editors). - -Account+Authentication+Password+Session components - -

- - -Recognized arguments: - -Description: - -Each component of the module has the potential to invoke the desired -filter. The filter is always -The behavior of the module can be significantly altered by the -arguments passed to it in the - -Permitted values for -For the case of the account component. Either -For the case of the password component, - -Examples/suggested usage: - -At the time of writing there is little real use to be made of this -module. For fun you might try adding the following line to your -login's configuration entries - - -# -# An example to see how to configure login to transpose upper and -# lower case letters once the user has logged in(!) -# -login session required pam_filter.so \ - run1 /usr/sbin/pam_filter/upperLOWER - - - - - - diff --git a/doc/modules/pam_ftp.sgml b/doc/modules/pam_ftp.sgml deleted file mode 100644 index a9444733..00000000 --- a/doc/modules/pam_ftp.sgml +++ /dev/null @@ -1,93 +0,0 @@ - - -Anonymous access module - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author. - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: -prompts for email address of user; easily spoofed (XXX - needs work) - - - -Overview of module - -

-The purpose of this module is to provide a pluggable anonymous ftp -mode of access. - -Authentication component - -

- - -Recognized arguments: -Description: - -This module intercepts the user's name and password. If the name is -`` -The behavior of the module can be modified with the following flags: - - - -Examples/suggested usage: - -An example of the use of this module is provided in the configuration -file section . With care, this -module could be used to provide new/temporary account anonymous -login. - - - - diff --git a/doc/modules/pam_group.sgml b/doc/modules/pam_group.sgml deleted file mode 100644 index 0d8550d4..00000000 --- a/doc/modules/pam_group.sgml +++ /dev/null @@ -1,108 +0,0 @@ - - -The group access module - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author. - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: -Sensitive to Clean code base: - -System dependencies: -Requires an /etc/security/group.conf file. Can be compiled -with or without Network aware: -Only through correctly set - -Overview of module - -

-This module provides group-settings based on the user's name and the -terminal they are requesting a given service from. It takes note of -the time of day. - -Authentication component - -

- - -Recognized arguments: - -Description: - -This module does not authenticate the user, but instead it grants -group memberships (in the credential setting phase of the -authentication module) to the user. Such memberships are based on the -service they are applying for. The group memberships are listed in -text form in the /etc/security/group.conf file. - -Examples/suggested usage: - -For this module to function correctly there must be a correctly -formatted /etc/security/groups.conf file present. The format -of this file is as follows. Group memberships are given based on the -service application satisfying any combination of lines in the -configuration file. Each line (barring comments which are preceded by -` - -services ; ttys ; users ; times ; groups - - -Here the first four fields share the syntax of the pam_time -configuration file; /etc/security/pam_time.conf, and the last -field, the -As stated in above this module's usefulness relies on the file-systems -accessible to the user. The point being that once granted the -membership of a group, the user may attempt to create a -The pam_group module fuctions in parallel with the -/etc/group file. If the user is granted any groups based on -the behavior of this module, they are granted in addition to -those entries /etc/group (or equivalent). - - - - diff --git a/doc/modules/pam_issue.sgml b/doc/modules/pam_issue.sgml deleted file mode 100644 index 1f617e3b..00000000 --- a/doc/modules/pam_issue.sgml +++ /dev/null @@ -1,120 +0,0 @@ - - -Add issue file to user prompt - -Synopsis - -

- - -Module Name: -Author: -Ben Collins <bcollins@debian.org> - -Maintainer: -Author - -Management groups provided: -Authentication (pam_sm_authenticate) - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: - - - -Overview of module - -

-This module prepends the issue file (/etc/issue by default) when -prompting for a username. - -Authentication component - -

- - -Recognized arguments: -Description: -This module allows you to prepend an issue file to the username prompt. It -also by default parses escape codes in the issue file similar to some -common getty's (using \x format). -

-Recognized escapes: - - - - -

-The behavior of this module can be modified with one of the following -flags: - -

- - - - -Examples/suggested usage: - -login auth pam_issue.so issue=/etc/issue - - - - diff --git a/doc/modules/pam_krb4.sgml b/doc/modules/pam_krb4.sgml deleted file mode 100644 index 16ce8183..00000000 --- a/doc/modules/pam_krb4.sgml +++ /dev/null @@ -1,126 +0,0 @@ - - -The Kerberos 4 module. - -Synopsis - -

- - -Module Name: -Author: -Derrick J. Brashear <shadow@dementia.org> - -Maintainer: -Author. - -Management groups provided: -authentication; password; session - -Cryptographically sensitive: -uses API - -Security rating: - -Clean code base: - -System dependencies: -libraries - Network aware: -Gets Kerberos ticket granting ticket via a Kerberos key distribution -center reached via the network. - - - -Overview of module - -

-This module provides an interface for doing Kerberos verification of a -user's password, getting the user a Kerberos ticket granting ticket -for use with the Kerberos ticket granting service, destroying the -user's tickets at logout time, and changing a Kerberos password. - - Session component - -

- - -Recognized arguments: - -Description: - -This component of the module currently sets the user's Examples/suggested usage: - -This part of the module won't be terribly useful until we can change -the environment from within a - - Password component - -

- - -Recognized arguments: -Description: - -This component of the module changes a user's Kerberos password -by first getting and using the user's old password to get -a session key for the password changing service, then sending -a new password to that service. - -Examples/suggested usage: - -This should only be used with a real Kerberos v4 - - Authentication component - -

- - -Recognized arguments: -Description: - -This component of the module verifies a user's Kerberos password -by requesting a ticket granting ticket from the Kerberos server -and optionally using it to attempt to retrieve the local computer's -host key and verifying using the key file on the local machine if -one exists. - -It also writes out a ticket file for the user to use later, and -deletes the ticket file upon logout (not until Examples/suggested usage: - -This module can be used with a real Kerberos server using MIT -v4 Kerberos keys. The module or the system Kerberos libraries -may be modified to support AFS style Kerberos keys. Currently -this is not supported to avoid cryptography constraints. - - - - diff --git a/doc/modules/pam_lastlog.sgml b/doc/modules/pam_lastlog.sgml deleted file mode 100644 index a00f76b1..00000000 --- a/doc/modules/pam_lastlog.sgml +++ /dev/null @@ -1,119 +0,0 @@ - - -The last login module - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author - -Management groups provided: -auth - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -uses information contained in the /var/log/lastlog file. - -Network aware: - - - -Overview of module - -

-This session module maintains the /var/log/lastlog file. Adding -an open entry when called via the pam_open_seesion() function -and completing it when pam_close_session() is called. This -module can also display a line of information about the last login of -the user. If an application already performs these tasks, it is not -necessary to use this module. - -Session component - -

- - -Recognized arguments: -Description: - -

-This module can be used to provide a ``Last login on ...'' -message. when the user logs into the system from what ever application -uses the PAM libraries. In addition, the module maintains the -/var/log/lastlog file. - -

-The behavior of this module can be modified with one of the following -flags: - -

- -/var/log/lastlog file. - -/var/log/lastlog file does not contain any old entries -for the user, indicate that the user has never previously logged in -with a ``welcome..." message. - - - -Examples/suggested usage: - -This module can be used to indicate that the user has new mail when -they /etc/pam.d/XXX file: - - -# -# When were we last here? -# -session optional pam_lastlog.so - - - -

-Note, some applications may perform this function themselves. In such -cases, this module is not necessary. - - - - diff --git a/doc/modules/pam_limits.sgml b/doc/modules/pam_limits.sgml deleted file mode 100644 index 44f057c4..00000000 --- a/doc/modules/pam_limits.sgml +++ /dev/null @@ -1,247 +0,0 @@ - - -The resource limits module - -Synopsis - -

- - -Module Name: -Authors: -Cristian Gafton <gafton@redhat.com> -Thanks are also due to Elliot Lee <sopwith@redhat.com> -for his comments on improving this module. - -Maintainer: -Cristian Gafton - 1996/11/20 - -Management groups provided: -session - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -requires an /etc/security/limits.conf file and kernel support -for resource limits. Also uses the library, Network aware: - - - -Overview of module - -

-This module, through the Session component - -

- - -Recognized arguments: -conf=/path/to/file.conf; change_uid; -utmp_early - -Description: - -Through the contents of the configuration file, -/etc/security/limits.conf, resource limits are placed on -users' sessions. Users of -The behavior of this module can be modified with the following -arguments: - - -conf=/path/to/file.conf - -indicate an alternative - -Examples/suggested usage: - -In order to use this module the system administrator must first create -a /etc/security/limits.conf). This file describes the resource -limits the superuser wishes to impose on users and groups. No limits -are imposed on -Each line of the configuration file describes a limit for a user in -the form: - - - - - - -

-The fields listed above should be filled as follows... -<domain> can be: - - a username - a groupname, with @group syntax - the wild-card the wild-card %group syntax - - -

-<type> can have the three values: - - - - -

-<item> can be one of the following: - - - -

-Note, if you specify a type of ``-'' but neglect to supply the - -In general, individual limits have priority over group limits, so if -you impose no limits for -Also, please note that all limit settings are set -In the -The -The following is an example configuration file: - - -# EXAMPLE /etc/security/limits.conf file: -# ======================================= -# -* soft core 0 -* hard rss 10000 -@student hard nproc 20 -@faculty soft nproc 20 -@faculty hard nproc 50 -ftp hard nproc 0 -@student - maxlogins 4 - - -Note, the use of -Note, that wild-cards - %group is specified - -See the following examples: - - -# EXAMPLE /etc/security/limits.conf file: -# -* - maxlogins 2 -@faculty - maxlogins 4 -% - maxlogins 30 -%student - maxlogins 10 - - -Explanation: every user can login 2 times, members of the -For the services that need resources limits (login for example) put -the following line in /etc/pam.conf as the last line for that -service (usually after the pam_unix session line: - - -# -# Resource limits imposed on login sessions via pam_limits -# -login session required pam_limits.so - - - - - - diff --git a/doc/modules/pam_listfile.sgml b/doc/modules/pam_listfile.sgml deleted file mode 100644 index 3754f57e..00000000 --- a/doc/modules/pam_listfile.sgml +++ /dev/null @@ -1,138 +0,0 @@ - - -The list-file module - -Synopsis - -

- - -Module Name: -Author: -Elliot Lee <sopwith@cuc.edu> - -Maintainer: -Red Hat Software: -Michael K. Johnson <johnsonm@redhat.com> 1996/11/18 -(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: -clean - -System dependencies: - -Network aware: - - - -Overview of module - -

-The list-file module provides a way to deny or allow services based on -an arbitrary file. - -Authentication component - -

- - -Recognized arguments: - -onerr=succeed|fail; -sense=allow|deny; -file=filename; -item=user|tty|rhost|ruser|group|shell -apply=user|@group - -Description: - -The module gets the item of the type specified -- user specifies -the username, PAM_USER; tty specifies the name of the terminal -over which the request has been made, PAM_TTY; rhost specifies -the name of the remote host (if any) from which the request was made, -PAM_RHOST; and ruser specifies the name of the remote user -(if available) who made the request, PAM_RUSER -- and looks for -an instance of that item in the file filename. filename -contains one line per item listed. If the item is found, then if -sense=allow, PAM_SUCCESS is returned, causing the -authorization request to succeed; else if sense=deny, -PAM_AUTH_ERR is returned, causing the authorization -request to fail. - -

-If an error is encountered (for instance, if filename -does not exist, or a poorly-constructed argument is encountered), -then if onerr=succeed, PAM_SUCCESS is returned, -otherwise if onerr=fail, PAM_AUTH_ERR or -PAM_SERVICE_ERR (as appropriate) will be returned. - -

-An additional argument, apply=, can be used to restrict the -application of the above to a specific user -(apply=username) or a given group -(apply=@groupname). This added restriction is only -meaningful when used with the -Besides this last one, all arguments should be specified; do not count -on any default behavior, as it is subject to change. - -

-No credentials are awarded by this module. - -Examples/suggested usage: - -Classic ``ftpusers'' authentication can be implemented with this entry -in /etc/pam.conf: - - -# -# deny ftp-access to users listed in the /etc/ftpusers file -# -ftp auth required pam_listfile.so \ - onerr=succeed item=user sense=deny file=/etc/ftpusers - - -Note, users listed in /etc/ftpusers file are -(counterintuitively) -To allow login access only for certain users, you can use a - - -# -# permit login to users listed in /etc/loginusers -# -login auth required pam_listfile.so \ - onerr=fail item=user sense=allow file=/etc/loginusers - - - -

-For this example to work, all users who are allowed to use the login -service should be listed in the file /etc/loginusers. Unless -you are explicitly trying to lock out root, make sure that when you do -this, you leave a way for root to log in, either by listing root in -/etc/loginusers, or by listing a user who is able to - - diff --git a/doc/modules/pam_mail.sgml b/doc/modules/pam_mail.sgml deleted file mode 100644 index 78ae95dc..00000000 --- a/doc/modules/pam_mail.sgml +++ /dev/null @@ -1,142 +0,0 @@ - - -The mail module - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author - -Management groups provided: -Authentication (credential) -Session (open) - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Default mail directory /var/spool/mail/ - -Network aware: - - - -Overview of module - -

-This module looks at the user's mail directory and indicates -whether the user has any mail in it. - -Session component - -

- - -Recognized arguments: -Description: - -This module provides the ``you have new mail'' service to the user. It -can be plugged into any application that has credential hooks. It gives a -single message indicating the -The behavior of this module can be modified with one of the following -flags: - -

- -/var/spool/mail. Note, if the supplied /var/spool/mail/u/s/user. - - - -Examples/suggested usage: - -This module can be used to indicate that the user has new mail when -they /etc/pam.conf file: - - -# -# do we have any mail? -# -login session optional pam_mail.so - - - -

-Note, if the mail spool file (be it /var/spool/mail/$USER or -a pathname given with the dir= parameter) is a directory then -pam_mail assumes it is in the Qmail Maildir format. - -

-Note, some applications may perform this function themselves. In such -cases, this module is not necessary. - - - -Authentication component - -

-Then authentication companent works the same as the session component, -except that everything is done during the pam_setcred() phase. - - diff --git a/doc/modules/pam_mkhomedir.sgml b/doc/modules/pam_mkhomedir.sgml deleted file mode 100644 index 075e16f9..00000000 --- a/doc/modules/pam_mkhomedir.sgml +++ /dev/null @@ -1,83 +0,0 @@ - - -Create home directories on initial login - -Synopsis - -

- - -Module Name: -Author: -Jason Gunthorpe <jgg@ualberta.ca> - -Maintainer: -Ben Collins <bcollins@debian.org> - -Management groups provided: -Session - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: - - - -Overview of module - -

-Creates home directories on the fly for authenticated users. - -Session component - -

- - -Recognized arguments: -Description: -This module is useful for distributed systems where the user account is -managed in a central database (such as NIS, NIS+, or LDAP) and accessed -through miltiple systems. It frees the administrator from having to create -a default home directory on each of the systems by creating it upon the -first succesfully authenticated login of that user. The skeleton directory -(usually /etc/skel/) is used to copy default files and also set's a umask -for the creation. - -

-The behavior of this module can be modified with one of the following -flags: - -

- - - - -Examples/suggested usage: - -session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 - - - - diff --git a/doc/modules/pam_motd.sgml b/doc/modules/pam_motd.sgml deleted file mode 100644 index 8ddc6392..00000000 --- a/doc/modules/pam_motd.sgml +++ /dev/null @@ -1,77 +0,0 @@ - - -Output the motd file - -Synopsis - -

- - -Module Name: -Author: -Ben Collins <bcollins@debian.org> - -Maintainer: -Author - -Management groups provided: -Session (open) - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: - - - -Overview of module - -

-This module outputs the motd file (/etc/motd by default) upon -successful login. - -Session component - -

- - -Recognized arguments: -Description: -This module allows you to have arbitrary motd's (message of the day) -output after a succesful login. By default this file is /etc/motd, -but is configurable to any file. - -

-The behavior of this module can be modified with one of the following -flags: - -

- - - - -Examples/suggested usage: - -login session pam_motd.so motd=/etc/motd - - - - diff --git a/doc/modules/pam_nologin.sgml b/doc/modules/pam_nologin.sgml deleted file mode 100644 index 52cf02a5..00000000 --- a/doc/modules/pam_nologin.sgml +++ /dev/null @@ -1,81 +0,0 @@ - - -The no-login module - -Synopsis - -

- - -Module Name: -Author: -Written by Michael K. Johnson <johnsonm@redhat.com> - -Maintainer: - -Management groups provided: -account; authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: - - - -Overview of module - -

-Provides standard Unix Authentication component - -

- - -Recognized arguments: -successok, file=<Description: - -Provides standard Unix /etc/nologin exists, only root is allowed to log in; other -users are turned away with an error message (and the module returns -/etc/nologin. - -

-If the file /etc/nologin does not exist, this module defaults -to returning -The administrator can override the default nologin file with the -Examples/suggested usage: - -In order to make this module effective, all login methods should be -secured by it. It should be used as a required method listed -before any sufficient methods in order to get standard Unix -nologin semantics. Note, the use of - - diff --git a/doc/modules/pam_permit.sgml b/doc/modules/pam_permit.sgml deleted file mode 100644 index fe616ac3..00000000 --- a/doc/modules/pam_permit.sgml +++ /dev/null @@ -1,83 +0,0 @@ - - -The promiscuous module - -Synopsis - -

- - -Module Name: -pam_permit - -Author: -Andrew G. Morgan, <morgan@kernel.org> - -Maintainer: -Linux-PAM maintainer. - -Management groups provided: -account; authentication; password; session - -Cryptographically sensitive: - -Security rating: -VERY LOW. Use with extreme caution. - -Clean code base: -Clean. - -System dependencies: - -Network aware: - - - -Overview of module - -

-This module is very dangerous. It should be used with extreme -caution. Its action is always to permit access. It does nothing else. - -Account+Authentication+Password+Session components - -

- - -Recognized arguments: - -Description: - -No matter what management group, the action of this module is to -simply return -In the case of authentication, the user's name will be acquired. Many -applications become confused if this name is unknown. - -Examples/suggested usage: - -It is seldom a good idea to use this module. However, it does have -some legitimate uses. For example, if the system-administrator wishes -to turn off the account management on a workstation, and at the same -time continue to allow logins, then she might use the following -configuration file entry for login: - - -# -# add this line to your other login entries to disable account -# management, but continue to permit users to log in... -# -login account required pam_permit.so - - - - - - diff --git a/doc/modules/pam_pwdb.sgml b/doc/modules/pam_pwdb.sgml deleted file mode 100644 index 2ee102e1..00000000 --- a/doc/modules/pam_pwdb.sgml +++ /dev/null @@ -1,249 +0,0 @@ - - -The Password-Database module - -Synopsis - -

- - -Module Name: -pam_pwdb - -Author: -Cristian Gafton <gafton@redhat.com> -and Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Red Hat. - -Management groups provided: -account; authentication; password; session - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Requires properly configured Network aware: - - - -Overview of module - -

-This module is a pluggable replacement for the libpwdb. - -Account component - -

- - -Recognized arguments: -Description: - -The Examples/suggested usage: - -In its accounting mode, this module can be inserted as follows: - - -# -# Ensure users account and password are still active -# -login account required pam_pwdb.so - - - - - -Authentication component - -

- - -Recognized arguments: -Description: - -The -The default action of this module is to not permit the user access to -a service if their -When given the argument -The argument, nodelay, can be used to discourage the -authentication component from requesting a delay should the -authentication as a whole fail. The default action is for the module -to request a delay-on-failure of the order of one second. - -

-Remaining arguments, supported by the other functions of this module, -are silently ignored. Other arguments are logged as errors through - -A helper binary, pwdb_chkpwd, is provided to check the user's -password when it is stored in a read protected database. This binary -is very simple and will only check the password of the user invoking -it. It is called transparently on behalf of the user by the -authenticating component of this module. In this way it is possible -for applications like xlock to work without being setuid-root. - -

-The likeauth argument makes the module return the same value -when called as a credential setting module and an authentication -module. This will help libpam take a sane path through the auth -component of your configuration file. - -Examples/suggested usage: - -The correct functionality of this module is dictated by having an -appropriate /etc/pwdb.conf file, the user -databases specified there dictate the source of the authenticated -user's record. - - - -Password component - -

- - -Recognized arguments: -Description: - -This part of the -In the case of conventional unix databases (which store the password -encrypted) the -The -The argument -The -The Examples/suggested usage: - -An example of the stacking of this module with respect to the -pluggable password checking module, - -Session component - -

- - -Recognized arguments: - -Description: - -No arguments are recognized by this module component. Its action is -simply to log the username and the service-type to -Examples/suggested usage: - -The use of the session modules is straightforward: - - -# -# pwdb - unix like session opening and closing -# -login session required pam_pwdb.so - - - - - - diff --git a/doc/modules/pam_radius.sgml b/doc/modules/pam_radius.sgml deleted file mode 100644 index 2bc4a9cd..00000000 --- a/doc/modules/pam_radius.sgml +++ /dev/null @@ -1,117 +0,0 @@ - - -The RADIUS session module - -Synopsis - -

- - -Module Name: -Author: -Cristian Gafton <gafton@redhat.com> - -Maintainer: -Author. - -Management groups provided: -session - -Cryptographically sensitive: -This module does not deal with passwords - -Security rating: - -Clean code base: -gcc reports 1 warning when compiling /usr/include/rpc/clnt.h. -Hey, is not my fault ! - -System dependencies: - -Network aware: - -yes; this is a network module (independent of application). - - - -Overview of module - -

-This module is intended to provide the session service for users -authenticated with a RADIUS server. At the present stage, the only -option supported is the use of the RADIUS server as an accounting -server. - -Session component - -

- - -Recognized arguments: - -Description: - -This module is intended to provide the session service for users -authenticated with a RADIUS server. At the present stage, the only -option supported is the use of the RADIUS server as an -(There are few things which needs to be cleared out first in -the PAM project until one will be able to use this module and expect -it to magically start pppd in response to a RADIUS server command to -use PPP for this user, or to initiate a telnet connection to another -host, or to hang and call back the user using parameters provided in -the RADIUS server response. Most of these things are better suited for -the radius login application. I hope to make available Real Soon (tm) -patches for the login apps to make it work this way.) - -

-When opening a session, this module sends an ``Accounting-Start'' -message to the RADIUS server, which will log/update/whatever a -database for this user. On close, an ``Accounting-Stop'' message is -sent to the RADIUS server. - -

-This module has no other prerequisites for making it work. One can -install a RADIUS server just for fun and use it as a centralized -accounting server and forget about wtmp/last/sac etc. . - -Examples/suggested usage: - -For the services that need this module (/etc/pam.conf as the last line for that -service (usually after the pam_unix session line): - - -login session required pam_radius.so - - -Replace -This module make extensive use of the API provided in libpwdb -0.54preB or later. By default, it will read the radius server -configuration (hostname and secret) from /etc/raddb/server. -This is a default compiled into libpwdb, and curently there is no way to -modify this default without recompiling libpwdb. I am working on -extending the radius support from libpwdb to provide a possibility -to make this runtime-configurable. - -Also please note that libpwdb will require also the RADIUS -dictionary to be present (/etc/raddb/dictionary). - - - - - diff --git a/doc/modules/pam_rhosts.sgml b/doc/modules/pam_rhosts.sgml deleted file mode 100644 index 69885047..00000000 --- a/doc/modules/pam_rhosts.sgml +++ /dev/null @@ -1,164 +0,0 @@ - - -The rhosts module - -Synopsis - -

- - -Module Name: -Author: -Al Longyear <longyear@netcom.com> - -Maintainer: - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: -Clean. - -System dependencies: - -Network aware: -Standard - -Overview of module - -

-This module performs the standard network authentication for services, -as used by traditional implementations of Authentication component - -

- - -Recognized arguments: -Description: - -The authentication mechanism of this module is based on the contents -of two files; /etc/hosts.equiv (or #include <netdb.h>) and ~/.rhosts. Firstly, -hosts listed in the former file are treated as equivalent to the -localhost. Secondly, entries in the user's own copy of the latter file -is used to map "/etc/hosts.equiv and their remote account -is identical to their local one, or if their remote account has an -entry in their personal configuration file. - -

-Some restrictions are applied to the attributes of the user's personal -configuration file: it must be a regular file (as defined by - -The module authenticates a remote user (internally specified by the -item -In the case of /etc/host.equiv file is -hosts_equiv_rootok option -should be used. Instead, the superuser must have a correctly configured -personal configuration file. - -

-The behavior of the module is modified by flags: - - - - -/etc/hosts.equiv file. - - -/etc/hosts.equiv for superuser. Without this -option /etc/hosts.equiv is not consulted for the superuser account. -This option has no effect if the no_hosts_equiv option is used. - - -~/.rhosts. - - -~/.rhosts file must not be writable by anyone -other than its owner. This option overlooks group write access in the -case that the group owner of this file has the same name as the -user being authenticated. To lessen the security problems associated -with this option, the module also checks that the user is the only -member of their private group. - - - - -Examples/suggested usage: - -To allow users to login from trusted remote machines, you should try -adding the following line to your /etc/pam.conf file - - -# -# No passwords required for users from hosts listed above. -# -login auth sufficient pam_rhosts_auth.so no_rhosts - - -Note, in this example, the system administrator has turned off all -/etc/host.equiv file, by replacing - - diff --git a/doc/modules/pam_rootok.sgml b/doc/modules/pam_rootok.sgml deleted file mode 100644 index f6aa8a07..00000000 --- a/doc/modules/pam_rootok.sgml +++ /dev/null @@ -1,85 +0,0 @@ - - -The root access module - -Synopsis - -

- - -Module Name: -pam_rootok - -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Linux-PAM maintainer - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: -Clean. - -System dependencies: - -Network aware: - - - -Overview of module - -

-This module is for use in situations where the superuser wishes -to gain access to a service without having to enter a password. - -Authentication component - -

- - -Recognized arguments: -Description: - -This module authenticates the user if their Examples/suggested usage: - -In the case of the - -# -# su authentication. Root is granted access by default. -# -su auth sufficient pam_rootok.so -su auth required pam_unix_auth.so - - - -

-Note. For programs that are run by the superuser (or started when the -system boots) this module should not be used to authenticate users. - - - - diff --git a/doc/modules/pam_securetty.sgml b/doc/modules/pam_securetty.sgml deleted file mode 100644 index ceb1358c..00000000 --- a/doc/modules/pam_securetty.sgml +++ /dev/null @@ -1,72 +0,0 @@ - - -The securetty module - -Synopsis - -

- - -Module Name: -Author[s]: -Elliot Lee <sopwith@cuc.edu> - -Maintainer: -Red Hat Software: - -(if unavailable, contact Elliot Lee <sopwith@cuc.edu>). - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -/etc/securetty file - -Network aware: - -Requires the application to fill in the PAM_TTY item -correctly in order to act meaningfully. - - - -Overview of module - -

-Provides standard Unix securetty checking. - -Authentication component - -

- - -Recognized arguments: - -Description: - -Provides standard Unix securetty checking, which causes authentication -for root to fail unless PAM_TTY is set to a string listed in -the /etc/securetty file. For all other users, it succeeds. - -Examples/suggested usage: - -For canonical usage, should be listed as a required -authentication method before any sufficient authentication -methods. - - - - diff --git a/doc/modules/pam_tally.sgml b/doc/modules/pam_tally.sgml deleted file mode 100644 index eeb05518..00000000 --- a/doc/modules/pam_tally.sgml +++ /dev/null @@ -1,191 +0,0 @@ - - -The login counter (tallying) module - -Synopsis - -

- - -Module Name: -pam_tally - -Author[s]: -Tim Baverstock - -Maintainer: - -Management groups provided: -auth; account - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -A faillog file (default location /var/log/faillog) - -Network aware: - - - -Overview of module - -

-This module maintains a count of attempted accesses, can reset count -on success, can deny access if too many attempts fail. - -

-pam_tally comes in two parts: pam_tally.so and -pam_tally. The former is the PAM module and the latter, a -stand-alone program. pam_tally is an (optional) application -which can be used to interrogate and manipulate the counter file. It -can display users' counts, set individual counts, or clear all -counts. Setting artificially high counts may be useful for blocking -users without changing their passwords. For example, one might find it -useful to clear all counts every midnight from a cron job. - -

-The counts file is organized as a binary-word array, indexed by -uid. You can probably make sense of it with od, if you don't -want to use the supplied appliction. - -

-Note, there are some outstanding issues with this module: -pam_tally is very dependant on getpw*() - a database -of usernames would be much more flexible; the `keep a count of current -logins' bit has been #ifdef'd out and you can only reset the -counter on successful authentication, for now. - -Generic options accepted by both components -

- - onerr=(succeed|fail): - if something weird happens, such as unable to open the file, how - should the module react? - file=/where/to/keep/counts: - specify the file location for the counts. - The default location is /var/log/faillog. - - -Authentication component - -

- - -Recognized arguments: -onerr=(succeed|fail); -file=/where/to/keep/counts; -no_magic_root - -Description: - -

-The authentication component of this module increments the attempted -login counter. - -

-Examples/suggested usage: - -

-The module argument no_magic_root is used to indicate that if -the module is invoked by a user with uid=0, then the counter is -incremented. The sys-admin should use this for daemon-launched -services, like telnet/rsh/login. For user -launched services, like su, this argument should be omitted. - -

-By way of more explanation, when a process already running as root -tries to access some service, the access is magic, and -bypasses pam_tally's checks: this is handy for suing -from root into an account otherwise blocked. However, for services -like telnet or login, which always effectively run -from the root account, root (ie everyone) shouldn't be granted this -magic status, and the flag `no_magic_root' should be set in this -situation, as noted in the summary above. - - - -Account component - -

- - -Recognized arguments: -onerr=(succeed|fail); -file=/where/to/keep/counts; -deny=n; -no_magic_root; -even_deny_root_account; -reset; -no_reset; -per_user; -no_lock_time - -Description: - -

-The account component can deny access and/or reset the attempts -counter. It also checks to make sure that the counts file is a plain -file and not world writable. - -Examples/suggested usage: - -

-The deny=n option is used to deny access if tally -for this user exceeds n. The presence of -deny=n changes the default for -reset/no_reset to reset, unless the user -trying to gain access is root and the no_magic_root option -has NOT been specified. - -

-The no_magic_root option ensures that access attempts by root -DON'T ignore deny. Use this for daemon-based stuff, like -telnet/rsh/login. - -

-The even_deny_root_account option is used to ensure that the -root account can become unavailable. Note that magic root -trying to gain root bypasses this, but normal users can be locked out. - -

-The reset option instructs the module to reset count to 0 on -successful entry, even for magic root. The no_reset option is -used to instruct the module to not reset the count on successful -entry. This is the default unless deny exists and the user -attempting access is NOT magic root. - -

-If /var/log/faillog contains a non-zero .fail_max -field for this user then the per_user module argument will -ensure that the module uses this value and not the global -deny=n parameter. - -

-The no_lock_time option is for ensuring that the module does -not use the .fail_locktime field in /var/log/faillog for this -user. - -

-Normally, failed attempts to access root will NOT cause the -root account to become blocked, to prevent denial-of-service: if your -users aren't given shell accounts and root may only login via -su or at the machine console (not -telnet/rsh, etc), this is safe. If you really want -root to be blocked for some given service, use -even_deny_root_account. - - - - diff --git a/doc/modules/pam_time.sgml b/doc/modules/pam_time.sgml deleted file mode 100644 index 8c5f677f..00000000 --- a/doc/modules/pam_time.sgml +++ /dev/null @@ -1,166 +0,0 @@ - - -Time control - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author - -Management groups provided: -account - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Requires a configuration file /etc/security/time.conf - -Network aware: -Through the - -Overview of module - -

-Running a well regulated system occasionally involves restricting -access to certain services in a selective manner. This module offers -some time control for access to services offered by a system. Its -actions are determined with a configuration file. This module can be -configured to deny access to (individual) users based on their name, -the time of day, the day of week, the service they are applying for -and their terminal from which they are making their request. - -Account component - -

- - -Recognized arguments: - -Description: - -This module bases its actions on the rules listed in its configuration -file: /etc/security/time.conf. Each rule has the following -form, - - -In words, each rule occupies a line, terminated with a newline or the -beginning of a comment; a ` - - -By a logic list we mean a sequence of tokens (associated with the -appropriate !morgan&!root, indicating that this rule -does not apply to the user morgan nor to root; and -tty*&!ttyp*, which indicates that the rule applies only -to console terminals but not pseudoterminals. - - - -Mo Tu We Th Fr Sa Su Wk Wd Al - - -The last two of these being -The time range part is a pair of 24-hour times, - -

-Note, that the given time restriction is only applied when the first -three fields are satisfied by a user's application for service. - -

-For convenience and readability a rule can be extended beyond a single -line with a `\Examples/suggested usage: - -The use of this module is initiated with an entry in the - - -# -# apply pam_time accounting to login requests -# -login account required pam_time.so - - -where, here we are applying the module to the -Some examples of rules that can be placed in the -/etc/security/time.conf configuration file are the following: - - -login ; tty* & !ttyp* ; !root ; !Al0000-2400 -all users except for games ; * ; !waster ; Wd0000-2400 | Wk1800-0800 -games (configured to use Linux-PAM) are only to be accessed out of -working hours. This rule does not apply to the user - -

-Note, currently there is no daemon enforcing the end of a session. -This needs to be remedied. - -

-Poorly formatted rules are logged as errors using - - diff --git a/doc/modules/pam_unix.sgml b/doc/modules/pam_unix.sgml deleted file mode 100644 index 286cd3f8..00000000 --- a/doc/modules/pam_unix.sgml +++ /dev/null @@ -1,288 +0,0 @@ - - -The Unix Password module - -Synopsis - -

- - -Module Name: -pam_unix - -Author: - -Maintainer: - -Management groups provided: -account; authentication; password; session - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: - - - -Overview of module - -

-This is the standard Unix authentication module. It uses standard calls -from the system's libraries to retrieve and set account information as -well as authentication. Usually this is obtained from the /etc/passwd -and the /etc/shadow file as well if shadow is enabled. - -Account component - -

- - -Recognized arguments: -Description: - -The Examples/suggested usage: - -In its accounting mode, this module can be inserted as follows: - - -# -# Ensure users account and password are still active -# -login account required pam_unix.so - - - - - -Authentication component - -

- - -Recognized arguments: -Description: - -The -The default action of this module is to not permit the user access to -a service if their -When given the argument -The argument, nodelay, can be used to discourage the -authentication component from requesting a delay should the -authentication as a whole fail. The default action is for the module -to request a delay-on-failure of the order of one second. - -

-Remaining arguments, supported by the other functions of this module, -are silently ignored. Other arguments are logged as errors through - -A helper binary, unix_chkpwd, is provided to check the user's -password when it is stored in a read protected database. This binary -is very simple and will only check the password of the user invoking -it. It is called transparently on behalf of the user by the -authenticating component of this module. In this way it is possible -for applications like xlock to work without being setuid-root. - -Examples/suggested usage: - -The correct functionality of this module is dictated by having an -appropriate /etc/nsswitch.conf file, the user -databases specified there dictate the source of the authenticated -user's record. -

-In its authentication mode, this module can be inserted as follows: - - -# -# Authenticate the user -# -login auth required pam_unix.so - - - - - -Password component - -

- - -Recognized arguments: -Description: - -This part of the -In the case of conventional unix databases (which store the password -encrypted) the -The -The argument -The -The -With the -The /etc/security/opasswd in order to force password change history -and keep the user from alternating between the same password too frequently. - -Examples/suggested usage: - -Standard usage: - - -# -# Change the users password -# -passwd password required pam_unix.so - - - -

-An example of the stacking of this module with respect to the -pluggable password checking module, - -# -# Change the users password -# -passwd password required pam_cracklib.so retry=3 minlen=6 difok=3 -passwd password required pam_unix.so use_authtok nullok md5 - - - - - -Session component - -

- - -Recognized arguments: - -Description: - -No arguments are recognized by this module component. Its action is -simply to log the username and the service-type to -Examples/suggested usage: - -The use of the session modules is straightforward: - - -# -# session opening and closing -# -login session required pam_unix.so - - - - - - diff --git a/doc/modules/pam_userdb.sgml b/doc/modules/pam_userdb.sgml deleted file mode 100644 index bdbf80b8..00000000 --- a/doc/modules/pam_userdb.sgml +++ /dev/null @@ -1,112 +0,0 @@ - - -The userdb module - -Synopsis - -

- - -Module Name: -Author: -Cristian Gafton <gafton@redhat.com> - -Maintainer: -Author. - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Requires Berkeley DB. - -Network aware: - - - -Overview of module - -

-Look up users in a .db database and verify their password against -what is contained in that database. - -Authentication component - -

- - -Recognized arguments: -Description: - -This module is used to verify a username/password pair against values stored in -a Berkeley DB database. The database is indexed by the username, and the data -fields corresponding to the username keys are the passwords, in unencrypted form, -so caution must be exercised over the access rights to the DB database itself.. - -The module will read the password from the user using the conversation mechanism. If -you are using this module on top of another authetication module (like -The action of the module may be modified from this default by one or -more of the following flags in the /etc/pam.d/<service> file. - - - - - -/etc/foodata -instead of /etc/foodata.db. - - - -Examples/suggested usage: - -This is a normal ftp configuration file (usually placed as /etc/pam.d/ftp -on most systems) that will accept for login users whose username/password pairs are -provided in the /tmp/dbtest.db file: - - - -#%PAM-1.0 -auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed -auth sufficient pam_userdb.so icase db=/tmp/dbtest -auth required pam_pwdb.so shadow nullok try_first_pass -auth required pam_shells.so -account required pam_pwdb.so -session required pam_pwdb.so - - - - - - diff --git a/doc/modules/pam_warn.sgml b/doc/modules/pam_warn.sgml deleted file mode 100644 index 4c2e3e18..00000000 --- a/doc/modules/pam_warn.sgml +++ /dev/null @@ -1,67 +0,0 @@ - - -Warning logger module - -Synopsis - -

- - -Module Name: -Author: -Andrew G. Morgan <morgan@kernel.org> - -Maintainer: -Author. - -Management groups provided: -authentication; password - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: - -Network aware: -logs information about the remote user and host (if pam-items are known) - - - -Overview of module - -

-This module is principally for logging information about a -proposed authentication or application to update a password. - -Authentication+Password component - -

- - -Recognized arguments: - -Description: - -Log the service, terminal, user, remote user and remote host to -Examples/suggested usage: - -an example is provided in the configuration file section . - - - - diff --git a/doc/modules/pam_wheel.sgml b/doc/modules/pam_wheel.sgml deleted file mode 100644 index 8c07a8b7..00000000 --- a/doc/modules/pam_wheel.sgml +++ /dev/null @@ -1,125 +0,0 @@ - - -The wheel module - -Synopsis - -

- - -Module Name: -Author: -Cristian Gafton <gafton@redhat.com> - -Maintainer: -Author. - -Management groups provided: -authentication - -Cryptographically sensitive: - -Security rating: - -Clean code base: - -System dependencies: -Requires libpwdb. - -Network aware: - - - -Overview of module - -

-Only permit root access to members of the wheel (Authentication component - -

- - -Recognized arguments: -Description: - -This module is used to enforce the so-called -The action of the module may be modified from this default by one or -more of the following flags in the /etc/pam.conf file. - - - - - - - - -Examples/suggested usage: - -To restrict access to superuser status to the members of the - - -# -# root gains access by default (rootok), only wheel members can -# become root (wheel) but Unix authenticate non-root applicants. -# -su auth sufficient pam_rootok.so -su auth required pam_wheel.so -su auth required pam_unix_auth.so - - - - - - diff --git a/doc/pam_appl.sgml b/doc/pam_appl.sgml deleted file mode 100644 index 85a878a0..00000000 --- a/doc/pam_appl.sgml +++ /dev/null @@ -1,1782 +0,0 @@ - - - - -

- -The Linux-PAM Application Developers' Guide -<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> -<date>DRAFT v0.76 2001/12/08 -<abstract> -This manual documents what an application developer needs to know -about the <bf>Linux-PAM</bf> library. It describes how an application -might use the <bf>Linux-PAM</bf> library to authenticate users. In -addition it contains a description of the funtions to be found in -<tt/libpam_misc/ library, that can be used in general applications. -Finally, it contains some comments on PAM related security issues for -the application developer. -</abstract> - -<toc> - -<sect>Introduction - -<sect1>Synopsis - -<p> -For general applications that wish to use the services provided by -<bf/Linux-PAM/ the following is a summary of the relevant linking -information: -<tscreen> -<verb> -#include <security/pam_appl.h> - -cc -o application .... -lpam -ldl -</verb> -</tscreen> - -<p> -In addition to <tt/libpam/, there is a library of miscellaneous -functions that make the job of writing <em/PAM-aware/ applications -easier (this library is not covered in the DCE-RFC for PAM and is -specific to the Linux-PAM distribution): -<tscreen> -<verb> -... -#include <security/pam_misc.h> - -cc -o application .... -lpam -lpam_misc -ldl -</verb> -</tscreen> - -<sect1> Description - -<p> -<bf>Linux-PAM</bf> (Pluggable Authentication Modules for Linux) is a -library that enables the local system administrator to choose how -individual applications authenticate users. For an overview of the -<bf>Linux-PAM</bf> library see the <bf/Linux-PAM/ System -Administrators' Guide. - -<p> -It is the purpose of the <bf>Linux-PAM</bf> project to liberate the -development of privilege granting software from the development of -secure and appropriate authentication schemes. This is accomplished -by providing a documented library of functions that an application may -use for all forms of user authentication management. This library -dynamically loads locally configured authentication modules that -actually perform the authentication tasks. - -<p> -From the perspective of an application developer the information -contained in the local configuration of the PAM library should not be -important. Indeed it is intended that an application treat the -functions documented here as a ``black box'' that will deal with all -aspects of user authentication. ``All aspects'' includes user -verification, account management, session initialization/termination -and also the resetting of passwords (<em/authentication tokens/). - -<sect>Overview - -<p> -Most service-giving applications are restricted. In other words, -their service is not available to all and every prospective client. -Instead, the applying client must jump through a number of hoops to -convince the serving application that they are authorized to obtain -service. - -The process of <em/authenticating/ a client is what PAM is designed to -manage. In addition to authentication, PAM provides account -management, credential management, session management and -authentication-token (password changing) management services. It is -important to realize when writing a PAM based application that these -services are provided in a manner that is <bf>transparent</bf> to -the application. That is to say, when the application is written, no -assumptions can be made about <em>how</em> the client will be -authenticated. - -<p> -The process of authentication is performed by the PAM library via a -call to <tt>pam_authenticate()</tt>. The return value of this -function will indicate whether a named client (the <em>user</em>) has -been authenticated. If the PAM library needs to prompt the user for -any information, such as their <em>name</em> or a <em>password</em> -then it will do so. If the PAM library is configured to authenticate -the user using some silent protocol, it will do this too. (This -latter case might be via some hardware interface for example.) - -<p> -It is important to note that the application must leave all decisions -about when to prompt the user at the discretion of the PAM library. - -<p> -The PAM library, however, must work equally well for different styles -of application. Some applications, like the familiar <tt>login</tt> -and <tt>passwd</tt> are terminal based applications, exchanges of -information with the client in these cases is as plain text messages. -Graphically based applications, however, have a more sophisticated -interface. They generally interact with the user via specially -constructed dialogue boxes. Additionally, network based services -require that text messages exchanged with the client are specially -formatted for automated processing: one such example is <tt>ftpd</tt> -which prefixes each exchanged message with a numeric identifier. - -<p> -The presentation of simple requests to a client is thus something very -dependent on the protocol that the serving application will use. In -spite of the fact that PAM demands that it drives the whole -authentication process, it is not possible to leave such protocol -subtleties up to the PAM library. To overcome this potential problem, -the application provides the PAM library with a <em>conversation</em> -function. This function is called from <bf>within</bf> the PAM -library and enables the PAM to directly interact with the client. The -sorts of things that this conversation function must be able to do are -prompt the user with text and/or obtain textual input from the user -for processing by the PAM library. The details of this function are -provided in a later section. - -<p> -For example, the conversation function may be called by the PAM library -with a request to prompt the user for a password. Its job is to -reformat the prompt request into a form that the client will -understand. In the case of <tt>ftpd</tt>, this might involve prefixing -the string with the number <tt>331</tt> and sending the request over -the network to a connected client. The conversation function will -then obtain any reply and, after extracting the typed password, will -return this string of text to the PAM library. Similar concerns need -to be addressed in the case of an X-based graphical server. - -<p> -There are a number of issues that need to be addressed when one is -porting an existing application to become PAM compliant. A section -below has been devoted to this: Porting legacy applications. - -<p> -Besides authentication, PAM provides other forms of management. -Session management is provided with calls to -<tt>pam_open_session()</tt> and <tt>pam_close_session()</tt>. What -these functions actually do is up to the local administrator. But -typically, they could be used to log entry and exit from the system or -for mounting and unmounting the user's home directory. If an -application provides continuous service for a period of time, it -should probably call these functions, first open after the user is -authenticated and then close when the service is terminated. - -<p> -Account management is another area that an application developer -should include with a call to <tt/pam_acct_mgmt()/. This call will -perform checks on the good health of the user's account (has it -expired etc.). One of the things this function may check is whether -the user's authentication token has expired - in such a case the -application may choose to attempt to update it with a call to -<tt/pam_chauthtok()/, although some applications are not suited to -this task (<em>ftp</em> for example) and in this case the application -should deny access to the user. - -<p> -PAM is also capable of setting and deleting the users credentials with -the call <tt>pam_setcred()</tt>. This function should always be -called after the user is authenticated and before service is offered -to the user. By convention, this should be the last call to the PAM -library before the PAM session is opened. What exactly a credential -is, is not well defined. However, some examples are given in the -glossary below. - -<sect>The public interface to <bf>Linux-PAM</bf> - -<p> -Firstly, the relevant include file for the <bf>Linux-PAM</bf> library -is <tt><security/pam_appl.h></tt>. It contains the definitions -for a number of functions. After listing these functions, we collect -some guiding remarks for programmers. - -<sect1>What can be expected by the application - -<p> -Below we document those functions in the <bf/Linux-PAM/ library that -may be called from an application. - -<sect2>Initialization of Linux-PAM -<label id="pam-start-section"> - -<p> -<tscreen> -<verb> -extern int pam_start(const char *service_name, const char *user, - const struct pam_conv *pam_conversation, - pam_handle_t **pamh); -</verb> -</tscreen> - -<p> -This is the first of the <bf>Linux-PAM</bf> functions that must be -called by an application. It initializes the interface and reads the -system configuration file, <tt>/etc/pam.conf</tt> (see the -<bf/Linux-PAM/ System Administrators' Guide). Following a successful -return (<tt/PAM_SUCCESS/) the contents of <tt/*pamh/ is a handle that -provides continuity for successive calls to the <bf/Linux-PAM/ -library. The arguments expected by <tt/pam_start/ are as follows: the -<tt/service_name/ of the program, the <tt/user/name of the individual -to be authenticated, a pointer to an application-supplied -<tt/pam_conv/ structure and a pointer to a <tt/pam_handle_t/ -<em/pointer/. - -<p> -The <tt>pam_conv</tt> structure is discussed more fully in the section -<ref id="the-conversation-function" name="below">. The -<tt>pam_handle_t</tt> is a <em>blind</em> structure and the -application should not attempt to probe it directly for information. -Instead the <bf>Linux-PAM</bf> library provides the functions -<tt>pam_set_item</tt> and <tt>pam_get_item</tt>. These functions are -documented below. - -<sect2>Termination of the library -<label id="pam-end-section"> - -<p> -<tscreen> -<verb> -extern int pam_end(pam_handle_t *pamh, int pam_status); -</verb> -</tscreen> - -<p> -This function is the last function an application should call in the -<bf>Linux-PAM</bf> library. Upon return the handle <tt/pamh/ is no -longer valid and all memory associated with it will be invalid (likely -to cause a segmentation fault if accessed). - -<p> -Under normal conditions the argument <tt/pam_status/ has the value -PAM_SUCCESS, but in the event of an unsuccessful application for -service the appropriate <bf/Linux-PAM/ error-return value should be -used here. Note, <tt/pam_end()/ unconditionally shuts down the -authentication stack associated with the <tt/pamh/ handle. The value -taken by <tt/pam_status/ is used as an argument to the module specific -callback functions, <tt/cleanup()/ (see the <bf/Linux-PAM/ <htmlurl -url="pam_modules.html" name="Module Developers' Guide">). In this way, -the module can be given notification of the pass/fail nature of the -tear-down process, and perform any last minute tasks that are -appropriate to the module before it is unlinked. - -<sect2>Setting PAM items -<label id="pam-set-item-section"> - -<p> -<tscreen> -<verb> -extern int pam_set_item(pam_handle_t *pamh, int item_type, - const void *item); -</verb> -</tscreen> - -<p>This function is used to (re)set the value of one of the following -<bf/item_type/s: - -<p><descrip> -<tag><tt/PAM_SERVICE/</tag> - - The service name (which identifies that PAM stack that - <tt/libpam/ will use to authenticate the program). - -<tag><tt/PAM_USER/</tag> - - The username of the entity under who's identity service will - be given. That is, following authentication, <tt/PAM_USER/ - identifies the local entity that gets to use the - service. Note, this value can be mapped from something (eg., - "<tt/anonymous/") to something else (eg. "<tt/guest119/") by - any module in the PAM stack. As such an application should - consult the value of <tt/PAM_USER/ after each call to a - <tt/pam_*()/ function. - -<tag><tt/PAM_USER_PROMPT/</tag> - - The string used when prompting for a user's name. The default - value for this string is ``Please enter username: ''. - -<tag><tt/PAM_TTY/</tag> - - The terminal name: prefixed by <tt>/dev/</tt> if it is a - device file; for graphical, X-based, applications the value - for this item should be the <tt/$DISPLAY/ variable. - -<tag><tt/PAM_RUSER/</tag> - - The requesting entity: user's username for a locally - requesting user or a remote requesting user - generally an - application or module will attempt to supply the value that is - most strongly authenticated (a local account before a remote - one. The level of trust in this value is embodied in the - actual authentication stack associated with the application, - so it is ultimately at the discretion of the system - administrator. It should generally match the current - <tt/PAM_RHOST/ value. That is, "<tt/PAM_RUSER@PAM_RHOST/" - should always identify the requesting user. In some cases, - <tt/PAM_RUSER/ may be NULL. In such situations, it is unclear - who the requesting entity is. - -<tag><tt/PAM_RHOST/</tag> - - The requesting hostname (the hostname of the machine from - which the <tt/PAM_RUSER/ entity is requesting service). That - is "<tt/PAM_RUSER@PAM_RHOST/" does identify the requesting - user. "<tt/luser@localhost/" or "<tt/evil@evilcom.com/" are - valid "<tt/PAM_RUSER@PAM_RHOST/" examples. In some - applications, <tt/PAM_RHOST/ may be NULL. In such situations, - it is unclear where the authentication request is originating - from. - -<tag><tt/PAM_CONV/</tag> - - The conversation structure (see section <ref - id="the-conversation-function" name="below">). - -<tag><tt/PAM_FAIL_DELAY/</tag> A function pointer to redirect - centrally managed failure delays (see section <ref - id="the-failure-delay-function" name="below">). - -</descrip> - -<p> -For all <tt/item_type/s, other than <tt/PAM_CONV/ and -<tt/PAM_FAIL_DELAY/, <tt/item/ is a pointer to a <tt><NUL></tt> -terminated character string. In the case of <tt/PAM_CONV/, <tt/item/ -points to an initialized <tt/pam_conv/ structure (see section <ref -id="the-conversation-function" name="below">). In the case of -<tt/PAM_FAIL_DELAY/, <tt/item/ is a function pointer: <tt/void -(*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)/ (see -section <ref id="the-failure-delay-function" name="below">). - -<p> -A successful call to this function returns <tt/PAM_SUCCESS/. However, -the application should expect at least one the following errors: - -<p> -<descrip> -<tag><tt/PAM_SYSTEM_ERR/</tag> - The <tt/pam_handle_t/ passed as a first argument to this - function was invalid. -<tag><tt/PAM_PERM_DENIED/</tag> - An attempt was made to replace the conversation structure with - a <tt/NULL/ value. -<tag><tt/PAM_BUF_ERR/</tag> - The function ran out of memory making a copy of the item. -<tag><tt/PAM_BAD_ITEM/</tag> - The application attempted to set an undefined or inaccessible - item. -</descrip> - -<sect2>Getting PAM items -<label id="pam-get-item-section"> - -<p> -<tscreen> -<verb> -extern int pam_get_item(const pam_handle_t *pamh, int item_type, - const void **item); -</verb> -</tscreen> - -<p> -This function is used to obtain the value of the indicated -<tt/item_type/. Upon successful return, <tt/*item/ contains a pointer -to the value of the corresponding item. Note, this is a pointer to -the <em/actual/ data and should <em/not/ be <tt/free()/'ed or -over-written! - -<p> -A successful call is signaled by a return value of <tt/PAM_SUCCESS/. -However, the application should expect one of the following errors: - -<p> -<descrip> -<tag><tt/PAM_SYSTEM_ERR/</tag> - The <tt/pam_handle_t/ passed as a first argument to this - function was invalid. -<tag><tt/PAM_PERM_DENIED/</tag> - The value of <tt/item/ was <tt/NULL/. -<tag><tt/PAM_BAD_ITEM/</tag> - The application attempted to set an undefined or inaccessible - item. -</descrip> - -<p> -Note, in the case of an error, the contents of <tt/item/ is not -modified - that is, it retains its pre-call value. One should take -care to initialize this value prior to calling -<tt/pam_get_item()/. Since, if its value - despite the -<tt/pam_get_item()/ function failing - is to be used the consequences -are undefined. - -<sect2>Understanding errors -<label id="pam-strerror-section"> - -<p> -<tscreen> -<verb> -extern const char *pam_strerror(pam_handle_t *pamh, int errnum); -</verb> -</tscreen> - -<p> -This function returns some text describing the <bf>Linux-PAM</bf> -error associated with the argument <tt/errnum/. If the error is not -recognized ``<tt/Unknown Linux-PAM error/'' is returned. - -<sect2>Planning for delays -<label id="the-failure-delay-function"> - -<p> -<tscreen> -<verb> -extern int pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec); -</verb> -</tscreen> - -<p> -This function is offered by <bf/Linux-PAM/ to facilitate time delays -following a failed call to <tt/pam_authenticate()/ and before control -is returned to the application. When using this function the -application programmer should check if it is available with, -<tscreen> -<verb> -#ifdef PAM_FAIL_DELAY - .... -#endif /* PAM_FAIL_DELAY */ -</verb> -</tscreen> - - -<p> -Generally, an application requests that a user is authenticated by -<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or -<tt/pam_chauthtok()/. These functions call each of the <em/stacked/ -authentication modules listed in the relevant <bf/Linux-PAM/ -configuration file. As directed by this file, one of more of the -modules may fail causing the <tt/pam_...()/ call to return an error. -It is desirable for there to also be a pause before the application -continues. The principal reason for such a delay is security: a delay -acts to discourage <em/brute force/ dictionary attacks primarily, but -also helps hinder <em/timed/ (covert channel) attacks. - -<p> -The <tt/pam_fail_delay()/ function provides the mechanism by which an -application or module can suggest a minimum delay (of <tt/micro_sec/ -<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time -requested with this function. Should <tt/pam_authenticate()/ fail, -the failing return to the application is delayed by an amount of time -randomly distributed (by up to 25%) about this longest value. - -<p> -Independent of success, the delay time is reset to its zero default -value when <bf/Linux-PAM/ returns control to the application. - -<p> -For applications written with a single thread that are event driven in -nature, <tt/libpam/ generating this delay may be undesirable. Instead, -the application may want to register the delay in some other way. For -example, in a single threaded server that serves multiple -authentication requests from a single event loop, the application -might want to simply mark a given connection as blocked until an -application timer expires. For this reason, <bf/Linux-PAM/ supplies -the <tt/PAM_FAIL_DELAY/ item. It can be queried and set with -<tt/pam_get_item()/ and <tt/pam_set_item()/ respectively. The value -used to set it should be a function pointer of the following -prototype: - -<tscreen> -<verb> -void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr); -</verb> -</tscreen> - -The arguments being the <tt/retval/ return code of the module stack, -the <tt/usec_delay/ micro-second delay that libpam is requesting and -the <tt/appdata_ptr/ that the application has associated with the -current <tt/pamh/ (<tt/pam_handle_t/). This last value was set by the -application when it called <tt/pam_start/ or explicitly with -<tt/pam_set_item(... , PAM_CONV, ...)/. Note, if <tt/PAM_FAIL_DELAY/ -is unset (or set to <tt/NULL/), then <tt/libpam/ will perform any -delay. - -<sect2>Authenticating the user - -<p> -<tscreen> -<verb> -extern int pam_authenticate(pam_handle_t *pamh, int flags); -</verb> -</tscreen> - -<p> -This function serves as an interface to the authentication mechanisms -of the loaded modules. The single <em/optional/ flag, which may be -logically OR'd with <tt/PAM_SILENT/, takes the following value, - -<p><descrip> - -<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag> - Instruct the authentication modules to return -<tt/PAM_AUTH_ERR/ if the user does not have a registered -authorization token---it is set to <tt/NULL/ in the system database. -</descrip> - -<p> -The value returned by this function is one of the following: - -<p><descrip> - -<tag><tt/PAM_AUTH_ERR/</tag> - The user was not authenticated -<tag><tt/PAM_CRED_INSUFFICIENT/</tag> - For some reason the application does not have sufficient -credentials to authenticate the user. -<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag> - The modules were not able to access the authentication -information. This might be due to a network or hardware failure etc. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The supplied username is not known to the authentication -service -<tag><tt/PAM_MAXTRIES/</tag> - One or more of the authentication modules has reached its -limit of tries authenticating the user. Do not try again. - -</descrip> - -<p> -If one or more of the authentication modules fails to load, for -whatever reason, this function will return <tt/PAM_ABORT/. - -<sect2>Setting user credentials -<label id="pam-setcred-section"> - -<p> -<tscreen> -<verb> -extern int pam_setcred(pam_handle_t *pamh, int flags); -</verb> -</tscreen> - -<p> -This function is used to set the module-specific credentials of the -user. It is usually called after the user has been authenticated, -after the account management function has been called but before a -session has been opened for the user. - -<p> -A credential is something that the user possesses. It is some -property, such as a <em>Kerberos</em> ticket, or a supplementary group -membership that make up the uniqueness of a given user. On a Linux -(or UN*X system) the user's <tt>UID</tt> and <tt>GID</tt>'s are -credentials too. However, it has been decided that these properties -(along with the default supplementary groups of which the user is a -member) are credentials that should be set directly by the application -and not by PAM. - -<p> -This function simply calls the <tt/pam_sm_setcred/ functions of each -of the loaded modules. Valid <tt/flags/, any one of which, may be -logically OR'd with <tt/PAM_SILENT/, are: - -<p><descrip> -<tag><tt/PAM_ESTABLISH_CRED/</tag> - Set the credentials for the authentication service, -<tag><tt/PAM_DELETE_CRED/</tag> - Delete the credentials associated with the authentication service, -<tag><tt/PAM_REINITIALIZE_CRED/</tag> - Reinitialize the user credentials, and -<tag><tt/PAM_REFRESH_CRED/</tag> - Extend the lifetime of the user credentials. -</descrip> - -<p> -A successful return is signalled with <tt/PAM_SUCCESS/. Errors that -are especially relevant to this function are the following: - -<p><descrip> -<tag><tt/PAM_CRED_UNAVAIL/</tag> - A module cannot retrieve the user's credentials. -<tag><tt/PAM_CRED_EXPIRED/</tag> - The user's credentials have expired. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to an authentication module. -<tag><tt/PAM_CRED_ERR/</tag> - A module was unable to set the credentials of the user. -</descrip> - -<sect2>Account management - -<p> -<tscreen> -<verb> -extern int pam_acct_mgmt(pam_handle_t *pamh, int flags); -</verb> -</tscreen> - -<p> -This function is typically called after the user has been -authenticated. It establishes whether the user's account is healthy. -That is to say, whether the user's account is still active and whether -the user is permitted to gain access to the system at this time. -Valid flags, any one of which, may be logically OR'd with -<tt/PAM_SILENT/, and are the same as those applicable to the -<tt/flags/ argument of <tt/pam_authenticate/. - -<p> -This function simply calls the corresponding functions of each of the -loaded modules, as instructed by the configuration file, -<tt>/etc/pam.conf</tt>. - -<p> -The normal response from this function is <tt/PAM_SUCCESS/, however, -specific failures are indicated by the following error returns: - -<descrip> -<tag><tt/PAM_AUTHTOKEN_REQD/</tag> -The user <bf/is/ valid but their authentication token has -<em/expired/. The correct response to this return-value is to require -that the user satisfies the <tt/pam_chauthtok()/ function before -obtaining service. It may not be possible for some applications to do -this. In such cases, the user should be denied access until such time -as they can update their password. - -<tag><tt/PAM_ACCT_EXPIRED/</tag> - The user is no longer permitted to access the system. -<tag><tt/PAM_AUTH_ERR/</tag> - There was an authentication error. - -<tag><tt/PAM_PERM_DENIED/</tag> - The user is not permitted to gain access at this time. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to a module's account management -component. - -</descrip> - -<sect2>Updating authentication tokens -<label id="pam-chauthtok-section"> - -<p> -<tscreen> -<verb> -extern int pam_chauthtok(pam_handle_t *pamh, const int flags); -</verb> -</tscreen> - -<p> -This function is used to change the authentication token for a given -user (as indicated by the state associated with the handle, -<tt/pamh/). The following is a valid but optional flag which may be -logically OR'd with <tt/PAM_SILENT/, - -<descrip> -<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag> - This argument indicates to the modules that the users -authentication token (password) should only be changed if it has -expired. -</descrip> - -<p> -Note, if this argument is not passed, the application requires that -<em/all/ authentication tokens are to be changed. - -<p> -<tt/PAM_SUCCESS/ is the only successful return value, valid -error-returns are: - -<descrip> -<tag><tt/PAM_AUTHTOK_ERR/</tag> - A module was unable to obtain the new authentication token. - -<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag> - A module was unable to obtain the old authentication token. - -<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag> - One or more of the modules was unable to change the -authentication token since it is currently locked. - -<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag> - Authentication token aging has been disabled for at least one -of the modules. - -<tag><tt/PAM_PERM_DENIED/</tag> - Permission denied. - -<tag><tt/PAM_TRY_AGAIN/</tag> - Not all of the modules were in a position to update the -authentication token(s). In such a case none of the user's -authentication tokens are updated. - -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to the authentication token changing -service. - -</descrip> - -<sect2>Session initialization -<label id="pam-open-session-section"> - -<p> -<tscreen> -<verb> -extern int pam_open_session(pam_handle_t *pamh, int flags); -</verb> -</tscreen> - -<p> -This function is used to indicate that an authenticated session has -begun. It is used to inform the modules that the user is currently in -a session. It should be possible for the <bf>Linux-PAM</bf> library -to open a session and close the same session (see section <ref -id="pam-close-session-section" name="below">) from different -applications. - -<p> -Currently, this function simply calls each of the corresponding -functions of the loaded modules. The only valid flag is -<tt/PAM_SILENT/ and this is, of course, <em/optional/. - -<p> -If any of the <em/required/ loaded modules are unable to open a -session for the user, this function will return <tt/PAM_SESSION_ERR/. - -<sect2>Terminating sessions -<label id="pam-close-session-section"> - -<p> -<tscreen> -<verb> -extern int pam_close_session(pam_handle_t *pamh, int flags); -</verb> -</tscreen> - -<p> -This function is used to indicate that an authenticated session has -ended. It is used to inform the modules that the user is exiting a -session. It should be possible for the <bf>Linux-PAM</bf> library to -open a session and close the same session from different applications. - -<p> -This function simply calls each of the corresponding functions of the -loaded modules in the same order that they were invoked with -<tt/pam_open_session()/. The only valid flag is <tt/PAM_SILENT/ and -this is, of course, <em/optional/. - -<p> -If any of the <em/required/ loaded modules are unable to close a -session for the user, this function will return <tt/PAM_SESSION_ERR/. - -<sect2>Setting PAM environment variables -<label id="pam-putenv-section"> - -<p> -The <tt/libpam/ library associates with each PAM-handle (<tt/pamh/), a -set of <it/PAM environment variables/. These variables are intended to -hold the session environment variables that the user will inherit when -the session is granted and the authenticated user obtains access to -the requested service. For example, when <tt/login/ has finally given -the user a shell, the environment (as viewed with the command -<tt/env/) will be what <tt/libpam/ was maintaining as the PAM -environment for that service application. Note, these variables are not -the environment variables of the <tt/login/ application. This is -principally for two reasons: <tt/login/ may want to have an -environment that cannot be seen or manipulated by a user; and -<tt/login/ (or whatever the serving application is) may be maintaining -a number of parallel sessions, via different <tt/pamh/ values, at the -same time and a single environment may not be appropriately shared -between each of these. The PAM environment may contain variables -seeded by the applicant user's client program, for example, and as -such it is not appropriate for one applicant to interfere with the -environment of another applicant. - -<p> -<tscreen> -<verb> -extern int pam_putenv(pam_handle_t *pamh, const char *name_value); -</verb> -</tscreen> - -<p> -This function attempts to (re)set a <bf/Linux-PAM/ environment -variable. The <tt/name_value/ argument is a single <tt/NUL/ terminated -string of one of the following forms: -<descrip> -<tag>``<tt/NAME=value of variable/''</tag> - -In this case the environment variable of the given <tt/NAME/ is set to -the indicated value: ``<tt/value of variable/''. If this variable is -already known, it is overwritten. Otherwise it is added to the -<bf/Linux-PAM/ environment. - -<tag>``<tt/NAME=/''</tag> - -This function sets the variable to an empty value. It is listed -separately to indicate that this is the correct way to achieve such a -setting. - -<tag>``<tt/NAME/''</tag> - -Without an `<tt/=/' the <tt/pam_putenv()/ function will delete the -corresponding variable from the <bf/Linux-PAM/ environment. - -</descrip> - -<p> -Success is indicated with a return value of <tt/PAM_SUCCESS/. Failure -is indicated by one of the following returns: - -<descrip> -<tag><tt/PAM_PERM_DENIED/</tag> - name given is a <tt/NULL/ pointer - -<tag><tt/PAM_BAD_ITEM/</tag> - variable requested (for deletion) is not currently set - -<tag><tt/PAM_ABORT/</tag> - the <bf/Linux-PAM/ handle, <tt/pamh/, is corrupt - -<tag><tt/PAM_BUF_ERR/</tag> - failed to allocate memory when attempting update - -</descrip> - -<sect2>Getting a PAM environment variable -<label id="pam-getenv-section"> - -<p> -<tscreen> -<verb> -extern const char *pam_getenv(pam_handle_t *pamh, const char *name); -</verb> -</tscreen> - -<p> -Obtain the value of the indicated <bf/Linux-PAM/ environment -variable. On error, internal failure or the unavailability of the -given variable (unspecified), this function simply returns <tt/NULL/. - -<sect2>Getting the PAM environment -<label id="pam-getenvlist-section"> - -<p> -<tscreen> -<verb> -extern const char * const *pam_getenvlist(pam_handle_t *pamh); -</verb> -</tscreen> - -<p> -The PAM environment variables (see section <ref -id="pam-putenv-section" name="above">) are a complete set of enviroment -variables that are associated with a PAM-handle (<tt/pamh/). They -represent the contents of the <it/regular/ environment variables of -the authenticated user when service is granted. - -<p> -Th function, <tt>pam_getenvlist()</tt> returns a pointer to a complete, -<tt/malloc()/'d, copy of the PAM environment. It is a pointer to a -duplicated list of environment variables. It should be noted that -this memory will never be <tt/free()'d/ by <tt/libpam/. Once obtained -by a call to <tt/pam_getenvlist()/, <bf>it is the responsibility of -the calling application</bf> to <tt/free()/ this memory. - -<p> -The format of the memory is a <tt/malloc()/'d array of <tt/char */ -pointers, the last element of which is set to <tt/NULL/. Each of the -non-<tt/NULL/ entries in this array point to a <tt/NUL/ terminated and -<tt/malloc()/'d <tt/char/ string of the form: -<tt/"/<it/name/<tt/=/<it/value/<tt/"/. - -<p> -It is by design, and not a coincidence, that the format and contents -of the returned array matches that required for the third argument of -the <tt/execle(3)/ function call. - -<sect1>What is expected of an application - -<sect2>The conversation function -<label id="the-conversation-function"> - -<p> -An application must provide a ``conversation function''. It is used -for direct communication between a loaded module and the application -and will typically provide a means for the module to prompt the user -for a password etc. . The structure, <tt/pam_conv/, is defined by -including <tt><security/pam_appl.h></tt>; to be, - -<p> -<tscreen> -<verb> -struct pam_conv { - int (*conv)(int num_msg, - const struct pam_message **msg, - struct pam_response **resp, - void *appdata_ptr); - void *appdata_ptr; -}; -</verb> -</tscreen> - -<p> -It is initialized by the application before it is passed to the -library. The <em/contents/ of this structure are attached to the -<tt/*pamh/ handle. The point of this argument is to provide a -mechanism for any loaded module to interact directly with the -application program. This is why it is called a <em/conversation/ -structure. - -<p> -When a module calls the referenced <tt/conv()/ function, the argument -<tt/*appdata_ptr/ is set to the second element of this structure. - -<p> -The other arguments of a call to <tt/conv()/ concern the information -exchanged by module and application. That is to say, <tt/num_msg/ -holds the length of the array of pointers, <tt/msg/. After a -successful return, the pointer <tt/*resp/ points to an array of -<tt/pam_response/ structures, holding the application supplied text. -Note, <tt/*resp/ is an <tt/struct pam_response/ array and <em/not/ an -array of pointers. - -<p> -The message (from the module to the application) passing structure is -defined by <tt><security/pam_appl.h></tt> as: - -<p> -<tscreen> -<verb> -struct pam_message { - int msg_style; - const char *msg; -}; -</verb> -</tscreen> - -<p> -Valid choices for <tt/msg_style/ are: - -<p><descrip> -<tag><tt/PAM_PROMPT_ECHO_OFF/</tag> - Obtain a string without echoing any text -<tag><tt/PAM_PROMPT_ECHO_ON/</tag> - Obtain a string whilst echoing text -<tag><tt/PAM_ERROR_MSG/</tag> - Display an error -<tag><tt/PAM_TEXT_INFO/</tag> - Display some text. -</descrip> - -<p> -The point of having an array of messages is that it becomes possible -to pass a number of things to the application in a single call from -the module. It can also be convenient for the application that related -things come at once: a windows based application can then present a -single form with many messages/prompts on at once. - -<p> -In passing, it is worth noting that there is a descrepency between the -way Linux-PAM handles the <tt/const struct pam_message **msg/ -conversation function argument from the way that Solaris' PAM (and -derivitives, known to include HP/UX, <em/are there others?/) -does. Linux-PAM interprets the <tt/msg/ argument as entirely -equivalent to the following prototype <tt/const struct pam_message -*msg[]/ (which, in spirit, is consistent with the commonly used -prototypes for <tt/argv/ argument to the familiar <tt/main()/ -function: <tt/char **argv/; and <tt/char *argv[]/). Said another way -Linux-PAM interprets the <tt/msg/ argument as a pointer to an array of -<tt/num_meg/ read only 'struct pam_message' <em/pointers/. Solaris' -PAM implementation interprets this argument as a pointer to a pointer -to an array of <tt/num_meg/ <tt/pam_message/ structures. Fortunately, -perhaps, for most module/application developers when <tt/num_msg/ has -a value of one these two definitions are entirely -equivalent. Unfortunately, casually raising this number to two has led -to unanticipated compatibility problems. - -<p> -For what its worth the two known module writer work-arounds for trying -to maintain source level compatibility with both PAM implementations -are: -<itemize> -<item> never call the conversation function with <tt/num_msg/ greater -than one. -<item> set up <tt/msg/ as doubly referenced so both types of -conversation function can find the messages. That is, make -<p><tscreen> -<verb> -msg[n] = & (( *msg )[n]) -</verb> -</tscreen> -</itemize> -<p> -The response (from the application to the module) passing structure is -defined by including <tt><security/pam_appl.h></tt> as: - -<p><tscreen><verb> -struct pam_response { - char *resp; - int resp_retcode; -}; -</verb></tscreen> - -<p> -Currently, there are no definitions for <tt/resp_retcode/ values; the -normal value is <tt/0/. - -<p> -Prior to the 0.59 release of Linux-PAM, the length of the returned -<tt/pam_response/ array was equal to the number of <em/prompts/ (types -<tt/PAM_PROMPT_ECHO_OFF/ and <tt/PAM_PROMPT_ECHO_ON/) in the -<tt/pam_message/ array with which the conversation function was -called. This meant that it was not always necessary for the module to -<tt/free(3)/ the responses if the conversation function was only used -to display some text. - -<p> -Post Linux-PAM-0.59. The number of responses is always equal to the -<tt/num_msg/ conversation function argument. This is slightly easier -to program but does require that the response array is <tt/free(3)/'d -after every call to the conversation function. The index of the -responses corresponds directly to the prompt index in the -<tt/pam_message/ array. - -<p> -The maximum length of the <tt/pam_msg.msg/ and <tt/pam_response.resp/ -character strings is <tt/PAM_MAX_MSG_SIZE/. (This is not enforced by -Linux-PAM.) - -<p> -<tt/PAM_SUCCESS/ is the expected return value of this -function. However, should an error occur the application should not -set <tt/*resp/ but simply return <tt/PAM_CONV_ERR/. - -<p> -Note, if an application wishes to use two conversation functions, it -should activate the second with a call to <tt/pam_set_item()/. - -<p> -<bf>Notes:</bf> New item types are being added to the conversation -protocol. Currently Linux-PAM supports: <tt>PAM_BINARY_PROMPT</tt> -and <tt>PAM_BINARY_MSG</tt>. These two are intended for server-client -hidden information exchange and may be used as an interface for -maching-machine authentication. - -<sect1>Programming notes - -<p> -Note, all of the authentication service function calls accept the -token <tt/PAM_SILENT/, which instructs the modules to not send -messages to the application. This token can be logically OR'd with any -one of the permitted tokens specific to the individual function calls. -<tt/PAM_SILENT/ does not override the prompting of the user for -passwords etc., it only stops informative messages from being -generated. - -<sect>Security issues of <bf>Linux-PAM</bf> - -<p> -PAM, from the perspective of an application, is a convenient API for -authenticating users. PAM modules generally have no increased -privilege over that possessed by the application that is making use of -it. For this reason, the application must take ultimate responsibility -for protecting the environment in which PAM operates. - -<p> -A poorly (or maliciously) written application can defeat any -<bf/Linux-PAM/ module's authentication mechanisms by simply ignoring -it's return values. It is the applications task and responsibility to -grant privileges and access to services. The <bf/Linux-PAM/ library -simply assumes the responsibility of <em/authenticating/ the user; -ascertaining that the user <em/is/ who they say they are. Care should -be taken to anticipate all of the documented behavior of the -<bf/Linux-PAM/ library functions. A failure to do this will most -certainly lead to a future security breach. - -<sect1>Care about standard library calls - -<p> -In general, writers of authorization-granting applications should -assume that each module is likely to call any or <em/all/ `libc' -functions. For `libc' functions that return pointers to -static/dynamically allocated structures (ie. the library allocates the -memory and the user is not expected to `<tt/free()/' it) any module -call to this function is likely to corrupt a pointer previously -obtained by the application. The application programmer should either -re-call such a `libc' function after a call to the <bf/Linux-PAM/ -library, or copy the structure contents to some safe area of memory -before passing control to the <bf/Linux-PAM/ library. - -<p> -Two important function classes that fall into this category are -<tt>getpwnam(3)</tt> and <tt>syslog(3)</tt>. - -<sect1>Choice of a service name - -<p> -When picking the <em/service-name/ that corresponds to the first entry -in the <bf/Linux-PAM/ configuration file, the application programmer -should <bf/avoid/ the temptation of choosing something related to -<tt/argv[0]/. It is a trivial matter for any user to invoke any -application on a system under a different name and this should not be -permitted to cause a security breach. - -<p> -In general, this is always the right advice if the program is setuid, -or otherwise more privileged than the user that invokes it. In some -cases, avoiding this advice is convenient, but as an author of such an -application, you should consider well the ways in which your program -will be installed and used. (Its often the case that programs are not -intended to be setuid, but end up being installed that way for -convenience. If your program falls into this category, don't fall into -the trap of making this mistake.) - -<p> -To invoke some <tt/target/ application by another name, the user may -symbolically link the target application with the desired name. To be -precise all the user need do is, -<tscreen> -<verb> -ln -s /target/application ./preferred_name -</verb> -</tscreen> -and then <em/run/ <tt>./preferred_name</tt> - -<p> -By studying the <bf/Linux-PAM/ configuration file(s), an attacker can -choose the <tt/preferred_name/ to be that of a service enjoying -minimal protection; for example a game which uses <bf/Linux-PAM/ to -restrict access to certain hours of the day. If the service-name were -to be linked to the filename under which the service was invoked, it -is clear that the user is effectively in the position of dictating -which authentication scheme the service uses. Needless to say, this -is not a secure situation. - -<p> -The conclusion is that the application developer should carefully -define the service-name of an application. The safest thing is to make -it a single hard-wired name. - -<sect1>The conversation function - -<p> -Care should be taken to ensure that the <tt/conv()/ function is -robust. Such a function is provided in the library <tt/libpam_misc/ -(see <ref id="libpam-misc-section" name="below">). - -<sect1>The identity of the user - -<p> -The <bf/Linux-PAM/ modules will need to determine the identity of the -user who requests a service, and the identity of the user who grants -the service. These two users will seldom be the same. Indeed there -is generally a third user identity to be considered, the new (assumed) -identity of the user once the service is granted. - -<p> -The need for keeping tabs on these identities is clearly an issue of -security. One convention that is actively used by some modules is -that the identity of the user requesting a service should be the -current <tt/uid/ (userid) of the running process; the identity of the -privilege granting user is the <tt/euid/ (effective userid) of the -running process; the identity of the user, under whose name the -service will be executed, is given by the contents of the -<tt/PAM_USER/ <tt/pam_get_item(3)/. Note, modules can change the -values of <tt/PAM_USER/ and <tt/PAM_RUSER/ during any of the -<tt/pam_*()/ library calls. For this reason, the application should -take care to use the <tt/pam_get_item()/ every time it wishes to -establish who the authenticated user is (or will currently be). - -<p> -For network-serving databases and other applications that provide -their own security model (independent of the OS kernel) the above -scheme is insufficient to identify the requesting user. - -<p> -A more portable solution to storing the identity of the requesting -user is to use the <tt/PAM_RUSER/ <tt/pam_get_item(3)/. The -application should supply this value before attempting to authenticate -the user with <tt/pam_authenticate()/. How well this name can be -trusted will ultimately be at the discretion of the local -administrator (who configures PAM for your application) and a selected -module may attempt to override the value where it can obtain more -reliable data. If an application is unable to determine the identity -of the requesting entity/user, it should not call <tt/pam_set_item(3)/ -to set <tt/PAM_RUSER/. - -<p> -In addition to the <tt/PAM_RUSER/ item, the application should supply -the <tt/PAM_RHOST/ (<em/requesting host/) item. As a general rule, the -following convention for its value can be assumed: <tt/<unset>/ -= unknown; <tt/localhost/ = invoked directly from the local system; -<em/other.place.xyz/ = some component of the user's connection -originates from this remote/requesting host. At present, PAM has no -established convention for indicating whether the application supports -a trusted path to communication from this host. - -<sect1>Sufficient resources - -<p> -Care should be taken to ensure that the proper execution of an -application is not compromised by a lack of system resources. If an -application is unable to open sufficient files to perform its service, -it should fail gracefully, or request additional resources. -Specifically, the quantities manipulated by the <tt/setrlimit(2)/ -family of commands should be taken into consideration. - -<p> -This is also true of conversation prompts. The application should not -accept prompts of arbitrary length with out checking for resource -allocation failure and dealing with such extreme conditions gracefully -and in a mannor that preserves the PAM API. Such tolerance may be -especially important when attempting to track a malicious adversary. - -<sect>A library of miscellaneous helper functions -<label id="libpam-misc-section"> - -<p> -To aid the work of the application developer a library of -miscellaneous functions is provided. It is called <tt/libpam_misc/, -and contains functions for allocating memory (securely), a text based -conversation function, and routines for enhancing the standard -PAM-environment variable support. - -<sect1>Requirements - -<p> -The functions, structures and macros, made available by this library -can be defined by including <tt><security/pam_misc.h></tt>. It -should be noted that this library is specific to <bf/Linux-PAM/ and is -not referred to in the defining DCE-RFC (see <ref id="bibliography" -name="the bibliography">) below. - -<sect1>Macros supplied - -<sect2>Safe duplication of strings - -<p> -<tscreen> -<verb> -x_strdup(const char *s) -</verb> -</tscreen> - -<p> -This macro is a replacement for the <tt/xstrdup()/ function that was -present in earlier versions of the library and which clashed horribly -with a number of applications. It returns a duplicate copy of the -<tt/NUL/ terminated string, <tt/s/. <tt/NULL/ is returned if there is -insufficient memory available for the duplicate or if <tt/s/ is -<tt/NULL/ to begin with. - -<sect1>Functions supplied - -<sect2>A text based conversation function - -<p> -<tscreen> -<verb> -extern int misc_conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr); -</verb> -</tscreen> - -<p> -This is a function that will prompt the user with the appropriate -comments and obtain the appropriate inputs as directed by -authentication modules. - -<p> -In addition to simply slotting into the appropriate <tt/struct -pam_conv/, this function provides some time-out facilities. The -function exports five variables that can be used by an application -programmer to limit the amount of time this conversation function will -spend waiting for the user to type something. - -<p> -The five variables are as follows: -<descrip> -<tag><tt>extern time_t pam_misc_conv_warn_time;</tt></tag> - -This variable contains the <em/time/ (as returned by <tt/time()/) that -the user should be first warned that the clock is ticking. By default -it has the value <tt/0/, which indicates that no such warning will be -given. The application may set its value to sometime in the future, -but this should be done prior to passing control to the <bf/Linux-PAM/ -library. - -<tag><tt>extern const char *pam_misc_conv_warn_line;</tt></tag> - -Used in conjuction with <tt/pam_misc_conv_warn_time/, this variable is -a pointer to the string that will be displayed when it becomes time to -warn the user that the timeout is approaching. Its default value is -``..\a.Time is running out...\n'', but this can be changed -by the application prior to passing control to <bf/Linux-PAM/. - -<tag><tt>extern time_t pam_misc_conv_die_time;</tt></tag> - -This variable contains the <em/time/ (as returned by <tt/time()/) that -the conversation will time out. By default it has the value <tt/0/, -which indicates that the conversation function will not timeout. The -application may set its value to sometime in the future, this should -be done prior to passing control to the <bf/Linux-PAM/ library. - -<tag><tt>extern const char *pam_misc_conv_die_line;</tt></tag> - -Used in conjuction with <tt/pam_misc_conv_die_time/, this variable is -a pointer to the string that will be displayed when the conversation -times out. Its default value is ``..\a.Sorry, your time is -up!\n'', but this can be changed by the application prior to -passing control to <bf/Linux-PAM/. - -<tag><tt>extern int pam_misc_conv_died;</tt></tag> - -Following a return from the <bf/Linux-PAM/ libraray, the value of this -variable indicates whether the conversation has timed out. A value of -<tt/1/ indicates the time-out occurred. - -</descrip> - -<p> -The following two function pointers are available for supporting binary -prompts in the conversation function. They are optimized for the -current incarnation of the <tt/libpamc/ library and are subject to -change. -<descrip> -<tag><tt>extern int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t -*prompt_p);</tt></tag> - -This function pointer is initialized to <tt/NULL/ but can be filled -with a function that provides machine-machine (hidden) message -exchange. It is intended for use with hidden authentication protocols -such as RSA or Diffie-Hellman key exchanges. (This is still under -development.) - -<tag><tt>extern int (*pam_binary_handler_free)(void *appdata, -pamc_bp_t *delete_me);</tt></tag> - -This function pointer is initialized to <tt/PAM_BP_RENEW(delete_me, 0, -0)/, but can be redefined as desired by the application. - -</descrip> - -<sect2>Transcribing an environment to that of Linux-PAM -<p> -<tscreen> -<verb> -extern int pam_misc_paste_env(pam_handle_t *pamh, - const char * const * user_env); -</verb> -</tscreen> - -This function takes the supplied list of environment pointers and -<em/uploads/ its contents to the <bf/Linux-PAM/ environment. Success -is indicated by <tt/PAM_SUCCESS/. - -<sect2>Liberating a locally saved environment -<p> -<tscreen> -<verb> -extern char **pam_misc_drop_env(char **env); -</verb> -</tscreen> - -This function is defined to complement the <tt/pam_getenvlist()/ -function. It liberates the memory associated with <tt/env/, -<em/overwriting/ with <tt/0/ all memory before <tt/free()/ing it. - -<sect2>BSD like Linux-PAM environment variable setting -<p> -<tscreen> -<verb> -extern int pam_misc_setenv(pam_handle_t *pamh, const char *name, - const char *value, int readonly); -</verb> -</tscreen> - -This function performs a task equivalent to <tt/pam_putenv()/, its -syntax is, however, more like the BSD style function; <tt/setenv()/. -The <tt/name/ and <tt/value/ are concatenated with an ``<tt/=/'' to -form a <tt/name_value/ and passed to <tt/pam_putenv()/. If, however, -the <bf/Linux-PAM/ variable is already set, the replacement will only -be applied if the last argument, <tt/readonly/, is zero. - -<sect>Porting legacy applications - -<p> -The following is extracted from an email. I'll tidy it up later. - -<p> -The point of PAM is that the application is not supposed to have any -idea how the attached authentication modules will choose to -authenticate the user. So all they can do is provide a conversation -function that will talk directly to the user(client) on the modules' -behalf. - -<p> -Consider the case that you plug a retinal scanner into the login -program. In this situation the user would be prompted: "please look -into the scanner". No username or password would be needed - all this -information could be deduced from the scan and a database lookup. The -point is that the retinal scanner is an ideal task for a "module". - -<p> -While it is true that a pop-daemon program is designed with the POP -protocol in mind and no-one ever considered attaching a retinal -scanner to it, it is also the case that the "clean" PAM'ification of -such a daemon would allow for the possibility of a scanner module -being be attached to it. The point being that the "standard" -pop-authentication protocol(s) [which will be needed to satisfy -inflexible/legacy clients] would be supported by inserting an -appropriate pam_qpopper module(s). However, having rewritten popd -once in this way any new protocols can be implemented in-situ. - -<p> -One simple test of a ported application would be to insert the -<tt/pam_permit/ module and see if the application demands you type a -password... In such a case, <tt/xlock/ would fail to lock the -terminal - or would at best be a screen-saver, ftp would give password -free access to all etc.. Neither of these is a very secure thing to -do, but they do illustrate how much flexibility PAM puts in the hands -of the local admin. - -<p> -The key issue, in doing things correctly, is identifying what is part -of the authentication procedure (how many passwords etc..) the -exchange protocol (prefixes to prompts etc., numbers like 331 in the -case of ftpd) and what is part of the service that the application -delivers. PAM really needs to have total control in the -authentication "procedure", the conversation function should only -deal with reformatting user prompts and extracting responses from raw -input. - -<sect>Glossary of PAM related terms - -<p> -The following are a list of terms used within this document. - -<p> -<descrip> - -<tag>Authentication token</tag> -Generally, this is a password. However, a user can authenticate -him/herself in a variety of ways. Updating the user's authentication -token thus corresponds to <em>refreshing</em> the object they use to -authenticate themself with the system. The word password is avoided -to keep open the possibility that the authentication involves a -retinal scan or other non-textual mode of challenge/response. - -<tag>Credentials</tag> -Having successfully authenticated the user, PAM is able to establish -certain characteristics/attributes of the user. These are termed -<em>credentials</em>. Examples of which are group memberships to -perform privileged tasks with, and <em>tickets</em> in the form of -environment variables etc. . Some user-credentials, such as the -user's UID and GID (plus default group memberships) are not deemed to -be PAM-credentials. It is the responsibility of the application to -grant these directly. - -</descrip> - -<sect>An example application - -<p> -To get a flavor of the way a <tt/Linux-PAM/ application is written we -include the following example. It prompts the user for their password -and indicates whether their account is valid on the standard output, -its return code also indicates the success (<tt/0/ for success; <tt/1/ -for failure). - -<p> -<tscreen> -<verb> -/* - This program was contributed by Shane Watts - [modifications by AGM] - - You need to add the following (or equivalent) to the /etc/pam.conf file. - # check authorization - check_user auth required /usr/lib/security/pam_unix_auth.so - check_user account required /usr/lib/security/pam_unix_acct.so - */ - -#include <security/pam_appl.h> -#include <security/pam_misc.h> -#include <stdio.h> - -static struct pam_conv conv = { - misc_conv, - NULL -}; - -int main(int argc, char *argv[]) -{ - pam_handle_t *pamh=NULL; - int retval; - const char *user="nobody"; - - if(argc == 2) { - user = argv[1]; - } - - if(argc > 2) { - fprintf(stderr, "Usage: check_user [username]\n"); - exit(1); - } - - retval = pam_start("check_user", user, &ero;conv, &ero;pamh); - - if (retval == PAM_SUCCESS) - retval = pam_authenticate(pamh, 0); /* is user really user? */ - - if (retval == PAM_SUCCESS) - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ - - /* This is where we have been authorized or not. */ - - if (retval == PAM_SUCCESS) { - fprintf(stdout, "Authenticated\n"); - } else { - fprintf(stdout, "Not Authenticated\n"); - } - - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ - pamh = NULL; - fprintf(stderr, "check_user: failed to release authenticator\n"); - exit(1); - } - - return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ -} -</verb> -</tscreen> - -<sect>Files - -<p><descrip> - -<tag><tt>/usr/include/security/pam_appl.h</tt></tag> - -header file for <bf/Linux-PAM/ applications interface - -<tag><tt>/usr/include/security/pam_misc.h</tt></tag> - -header file for useful library functions for making applications -easier to write - -<tag><tt>/usr/lib/libpam.so.*</tt></tag> - -the shared library providing applications with access to -<bf/Linux-PAM/. - -<tag><tt>/etc/pam.conf</tt></tag> - -the <bf/Linux-PAM/ configuration file. - -<tag><tt>/usr/lib/security/pam_*.so</tt></tag> - -the primary location for <bf/Linux-PAM/ dynamically loadable object -files; the modules. - -</descrip> - -<sect>See also -<label id="bibliography"> - -<p><itemize> - -<item>The <bf/Linux-PAM/ -<htmlurl url="pam.html" name="System Administrators' Guide">. - -<item>The <bf/Linux-PAM/ -<htmlurl url="pam_modules.html" name="Module Writers' Guide">. - -<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH -PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request -For Comments 86.0, October 1995. - -</itemize> - -<sect>Notes - -<p> -I intend to put development comments here... like ``at the moment -this isn't actually supported''. At release time what ever is in -this section will be placed in the Bugs section below! :) - -<p> -<itemize> - -<item> <tt/pam_strerror()/ should be internationalized.... - -<item> -Note, the <tt/resp_retcode/ of struct <tt/pam_message/, has no -purpose at the moment. Ideas/suggestions welcome! - -<item> more security issues are required.... - -</itemize> - -<sect>Author/acknowledgments - -<p> -This document was written by Andrew G. Morgan -(morgan@kernel.org) with many contributions from -<!-- insert credits here --> -<!-- - an sgml list of people to credit for their contributions to Linux-PAM - $Id$ - --> -Chris Adams, -Peter Allgeyer, -Tim Baverstock, -Tim Berger, -Craig S. Bell, -Derrick J. Brashear, -Ben Buxton, -Seth Chaiklin, -Oliver Crow, -Chris Dent, -Marc Ewing, -Cristian Gafton, -Emmanuel Galanos, -Brad M. Garcia, -Eric Hester, -Roger Hu, -Eric Jacksch, -Michael K. Johnson, -David Kinchlea, -Olaf Kirch, -Marcin Korzonek, -Stephen Langasek, -Nicolai Langfeldt, -Elliot Lee, -Luke Kenneth Casson Leighton, -Al Longyear, -Ingo Luetkebohle, -Marek Michalkiewicz, -Robert Milkowski, -Aleph One, -Martin Pool, -Sean Reifschneider, -Jan Rekorajski, -Erik Troan, -Theodore Ts'o, -Jeff Uphoff, -Myles Uyema, -Savochkin Andrey Vladimirovich, -Ronald Wahl, -David Wood, -John Wilmes, -Joseph S. D. Yao -and -Alex O. Yuriev. - -<p> -Thanks are also due to Sun Microsystems, especially to Vipin Samar and -Charlie Lai for their advice. At an early stage in the development of -<bf/Linux-PAM/, Sun graciously made the documentation for their -implementation of PAM available. This act greatly accelerated the -development of <bf/Linux-PAM/. - -<sect>Bugs/omissions - -<p> -This manual is hopelessly unfinished. Only a partial list of people is -credited for all the good work they have done. - -<sect>Copyright information for this document - -<p> -Copyright (c) Andrew G. Morgan 1996-9,2000-1. All rights reserved. -<newline> -Email: <tt><morgan@kernel.org></tt> - -<p> -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -<p> -<itemize> - -<item> -1. Redistributions of source code must retain the above copyright - notice, and the entire permission notice in its entirety, - including the disclaimer of warranties. - -<item> -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -<item> -3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -</itemize> - -<p> -<bf/Alternatively/, this product may be distributed under the terms of -the GNU General Public License (GPL), in which case the provisions of -the GNU GPL are required <bf/instead of/ the above restrictions. -(This clause is necessary due to a potential bad interaction between -the GNU GPL and the restrictions contained in a BSD-style copyright.) - -<p> -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -<p> -<tt>$Id$</tt> - -</article> diff --git a/doc/pam_modules.sgml b/doc/pam_modules.sgml deleted file mode 100644 index c986e0a9..00000000 --- a/doc/pam_modules.sgml +++ /dev/null @@ -1,1505 +0,0 @@ -<!doctype linuxdoc system> - -<!-- - - $Id$ - - Copyright (c) Andrew G. Morgan 1996-2001. All rights reserved. - - ** some sections, in this document, were contributed by other - ** authors. They carry individual copyrights. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, and the entire permission notice in its entirety, - including the disclaimer of warranties. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -ALTERNATIVELY, this product may be distributed under the terms of the -GNU General Public License, in which case the provisions of the GNU -GPL are required INSTEAD OF the above restrictions. (This clause is -necessary due to a potential bad interaction between the GNU GPL and -the restrictions contained in a BSD-style copyright.) - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - - --> - -<article> - -<title>The Linux-PAM Module Writers' Guide -<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> -<date>DRAFT v0.76 2002/05/09 -<abstract> -This manual documents what a programmer needs to know in order to -write a module that conforms to the <bf/Linux-PAM/ standard. It also -discusses some security issues from the point of view of the module -programmer. -</abstract> - -<toc> - -<sect>Introduction - -<sect1> Synopsis -<p> -<tscreen> -<verb> -#include <security/pam_modules.h> - -gcc -fPIC -c pam_module-name.c -ld -x --shared -o pam_module-name.so pam_module-name.o -</verb> -</tscreen> - -<sect1> Description - -<p> -<bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a -library that enables the local system administrator to choose how -individual applications authenticate users. For an overview of the -<bf/Linux-PAM/ library see the <bf/Linux-PAM/ System Administrators' -Guide. - -<p> -A <bf/Linux-PAM/ module is a single executable binary file that can be -loaded by the <bf/Linux-PAM/ interface library. This PAM library is -configured locally with a system file, <tt>/etc/pam.conf</tt>, to -authenticate a user request via the locally available authentication -modules. The modules themselves will usually be located in the -directory <tt>/usr/lib/security</tt> and take the form of dynamically -loadable object files (see dlopen(3)). Alternatively, the modules can -be statically linked into the <bf/Linux-PAM/ library; this is mostly to -allow <bf/Linux-PAM/ to be used on platforms without dynamic linking -available, but the two forms can be used together. It is the -<bf/Linux-PAM/ interface that is called by an application and it is -the responsibility of the library to locate, load and call the -appropriate functions in a <bf/Linux-PAM/-module. - -<p> -Except for the immediate purpose of interacting with the user -(entering a password etc..) the module should never call the -application directly. This exception requires a "conversation -mechanism" which is documented below. - -<sect>What can be expected by the module - -<p> -Here we list the interface that the conventions that all -<bf/Linux-PAM/ modules must adhere to. - -<sect1>Getting and setting <tt/PAM_ITEM/s and <em/data/ - -<p> -First, we cover what the module should expect from the <bf/Linux-PAM/ -library and a <bf/Linux-PAM/ <em/aware/ application. Essesntially this -is the <tt/libpam.*/ library. - -<sect2> -Setting data - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_set_data(pam_handle_t *pamh, - const char *module_data_name, - void *data, - void (*cleanup)(pam_handle_t *pamh, - void *data, int error_status) ); -</verb> -</tscreen> - -<p> -The modules may be dynamically loadable objects. In general such files -should not contain <tt/static/ variables. This and the subsequent -function provide a mechanism for a module to associate some data with -the handle <tt/pamh/. Typically a module will call the -<tt/pam_set_data()/ function to register some data under a (hopefully) -unique <tt/module_data_name/. The data is available for use by other -modules too but <em/not/ by an application. - -<p> -The function <tt/cleanup()/ is associated with the <tt/data/ and, if -non-<tt/NULL/, it is called when this data is over-written or -following a call to <tt/pam_end()/ (see the Linux-PAM Application -Developers' Guide). - -<p> -The <tt/error_status/ argument is used to indicate to the module the -sort of action it is to take in cleaning this data item. As an -example, Kerberos creates a ticket file during the authentication -phase, this file might be associated with a data item. When -<tt/pam_end()/ is called by the module, the <tt/error_status/ -carries the return value of the <tt/pam_authenticate()/ or other -<tt/libpam/ function as appropriate. Based on this value the Kerberos -module may choose to delete the ticket file (<em/authentication -failure/) or leave it in place. - -<p> -The <tt/error_status/ may have been logically OR'd with either of the -following two values: - -<p> -<descrip> -<tag><tt/PAM_DATA_REPLACE/</tag> - When a data item is being replaced (through a second call to -<tt/pam_set_data()/) this mask is used. Otherwise, the call is assumed -to be from <tt/pam_end()/. - -<tag><tt/PAM_DATA_SILENT/</tag> - Which indicates that the process would prefer to perform the -<tt/cleanup()/ quietly. That is, discourages logging/messages to the -user. - -</descrip> - - -<sect2> -Getting data - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_get_data(const pam_handle_t *pamh, - const char *module_data_name, - const void **data); -</verb> -</tscreen> - -<p> -This function together with the previous one provides a method of -associating module-specific data with the handle <tt/pamh/. A -successful call to <tt/pam_get_data/ will result in <tt/*data/ -pointing to the data associated with the <tt/module_data_name/. Note, -this data is <em/not/ a copy and should be treated as <em/constant/ -by the module. - -<p> -Note, if there is an entry but it has the value <tt/NULL/, then this -call returns <tt/PAM_NO_MODULE_DATA/. - -<sect2> -Setting items - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_set_item(pam_handle_t *pamh, - int item_type, - const void *item); -</verb> -</tscreen> - -<p> -This function is used to (re)set the value of one of the -<tt/item_type/s. The reader is urged to read the entry for this -function in the <bf/Linux-PAM/ application developers' manual. - -<p> -In addition to the <tt/item/s listed there, the module can set the -following two <tt/item_type/s: - -<p> -<descrip> -<tag><tt/PAM_AUTHTOK/</tag> - -The authentication token (often a password). This token should be -ignored by all module functions besides <tt/pam_sm_authenticate()/ and -<tt/pam_sm_chauthtok()/. In the former function it is used to pass the -most recent authentication token from one stacked module to -another. In the latter function the token is used for another -purpose. It contains the currently active authentication token. - -<tag><tt/PAM_OLDAUTHTOK/</tag> - -The old authentication token. This token should be ignored by all -module functions except <tt/pam_sm_chauthtok()/. - -</descrip> - -<p> -Both of these items are reset before returning to the application. -When resetting these items, the <bf/Linux-PAM/ library first writes -<tt/0/'s to the current tokens and then <tt/free()/'s the associated -memory. - -<p> -The return values for this function are listed in the -<bf>Linux-PAM</bf> Application Developers' Guide. - -<sect2> -Getting items - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_get_item(const pam_handle_t *pamh, - int item_type, - const void **item); -</verb> -</tscreen> - -<p> -This function is used to obtain the value of the specified -<tt/item_type/. It is better documented in the <bf/Linux-PAM/ -Application Developers' Guide. However, there are three things worth -stressing here: -<itemize> - -<item> -Generally, if the module wishes to obtain the name of the user, it -should not use this function, but instead perform a call to -<tt/pam_get_user()/ (see section <ref id="pam-get-user" -name="below">). - -<item> -The module is additionally privileged to read the authentication -tokens, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/ (see the section -above on <tt/pam_set_data()/). - -<item> -The module should <em/not/ <tt/free()/ or alter the data pointed to by -<tt/*item/ after a successful return from <tt/pam_get_item()/. This -pointer points directly at the data contained within the <tt/*pamh/ -structure. Should a module require that a change is made to the this -<tt/ITEM/ it should make the appropriate call to <tt/pam_set_item()/. -</itemize> - -<sect2>The <em/conversation/ mechanism - -<p> -Following the call <tt>pam_get_item(pamh,PAM_CONV,&item)</tt>, the -pointer <tt/item/ points to a structure containing an a pointer to a -<em/conversation/-function that provides limited but direct access to -the application. The purpose of this function is to allow the module -to prompt the user for their password and pass other information in a -manner consistent with the application. For example, an X-windows -based program might pop up a dialog box to report a login -failure. Just as the application should not be concerned with the -method of authentication, so the module should not dictate the manner -in which input (output) is obtained from (presented to) to the user. - -<p> -<bf>The reader is strongly urged to read the more complete description of -the <tt/pam_conv/ structure, written from the perspective of the -application developer, in the <bf/Linux-PAM/ Application Developers' -Guide.</bf> - -<p> -The return values for this function are listed in the -<bf>Linux-PAM</bf> Application Developers' Guide. - -<p> -The <tt/pam_response/ structure returned after a call to the -<tt/pam_conv/ function must be <tt/free()/'d by the module. Since the -call to the conversation function originates from the module, it is -clear that this <tt/pam_response/ structure could be either statically -or dynamically (using <tt/malloc()/ etc.) allocated within the -application. Repeated calls to the conversation function would likely -overwrite static memory, so it is required that for a successful -return from the conversation function the memory for the response -structure is dynamically allocated by the application with one of the -<tt/malloc()/ family of commands and <em/must/ be <tt/free()/'d by the -module. - -<p> -If the <tt/pam_conv/ mechanism is used to enter authentication tokens, -the module should either pass the result to the <tt/pam_set_item()/ -library function, or copy it itself. In such a case, once the token -has been stored (by one of these methods or another one), the memory -returned by the application should be overwritten with <tt/0/'s, and -then <tt/free()/'d. - -There is a handy macro <tt/_pam_drop_reply()/ to be found in -<tt><security/_pam_macros.h></tt> that can be used to -conveniently cleanup a <tt/pam_response/ structure. (Note, this -include file is specific to the Linux-PAM sources, and whilst it will -work with Sun derived PAM implementations, it is not generally -distributed by Sun.) - -<sect2>Getting the name of a user<label id="pam-get-user"> - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_get_user(pam_handle_t *pamh, - const char **user, - const char *prompt); -</verb> -</tscreen> - -<p> -This is a <bf/Linux-PAM/ library function that returns the -(prospective) name of the user. To determine the username it does the -following things, in this order: -<itemize> - -<item> checks what <tt/pam_get_item(pamh, PAM_USER, ... );/ would have -returned. If this is not <tt/NULL/ this is what it returns. Otherwise, - -<item> obtains a username from the application via the <tt/pam_conv/ -mechanism, it prompts the user with the first non-<tt/NULL/ string in -the following list: -<itemize> - -<item> The <tt/prompt/ argument passed to the function -<item> What is returned by <tt/pam_get_item(pamh,PAM_USER_PROMPT, ... );/ -<item> The default prompt: ``Please enter username: '' - -</itemize> -</itemize> - -<p> -By whatever means the username is obtained, a pointer to it is -returned as the contents of <tt/*user/. Note, this memory should -<em/not/ be <tt/free()/'d by the module. Instead, it will be liberated -on the next call to <tt/pam_get_user()/, or by <tt/pam_end()/ when the -application ends its interaction with <bf/Linux-PAM/. - -<p> -Also, in addition, it should be noted that this function sets the -<tt/PAM_USER/ item that is associated with the <tt/pam_[gs]et_item()/ -function. - -<p> -The return value of this function is one of the following: -<itemize> - -<item> <tt/PAM_SUCCESS/ - username obtained. - -<item> <tt/PAM_CONV_AGAIN/ - converstation did not complete and the -caller is required to return control to the application, until such -time as the application has completed the conversation process. A -module calling <tt/pam_get_user()/ that obtains this return code, -should return <tt/PAM_INCOMPLETE/ and be prepared (when invoked the -next time) to recall <tt/pam_get_user()/ to fill in the user's name, -and then pick up where it left off as if nothing had happened. This -procedure is needed to support an event-driven application programming -model. - -<item> <tt/PAM_CONV_ERR/ - the conversation method supplied by the -application failed to obtain the username. - -</itemize> - -<sect2>Setting a Linux-PAM environment variable - -<p> -Synopsis: -<tscreen> -<verb> -extern int pam_putenv(pam_handle_t *pamh, const char *name_value); -</verb> -</tscreen> - -<p> -<bf/Linux-PAM/ comes equipped with a series of functions for -maintaining a set of <em/environment/ variables. The environment is -initialized by the call to <tt/pam_start()/ and is <bf/erased/ with a -call to <tt/pam_end()/. This <em/environment/ is associated with the -<tt/pam_handle_t/ pointer returned by the former call. - -<p> -The default environment is all but empty. It contains a single -<tt/NULL/ pointer, which is always required to terminate the -variable-list. The <tt/pam_putenv()/ function can be used to add a -new environment variable, replace an existing one, or delete an old -one. - -<p> -<itemize> -<item>Adding/replacing a variable<newline> - -To add or overwrite a <bf/Linux-PAM/ environment variable the value of -the argument <tt/name_value/, should be of the following form: -<tscreen> -<verb> -name_value="VARIABLE=VALUE OF VARIABLE" -</verb> -</tscreen> -Here, <tt/VARIABLE/ is the environment variable's name and what -follows the `<tt/=/' is its (new) value. (Note, that <tt/"VARIABLE="/ -is a valid value for <tt/name_value/, indicating that the variable is -set to <tt/""/.) - -<item> Deleting a variable<newline> - -To delete a <bf/Linux-PAM/ environment variable the value of -the argument <tt/name_value/, should be of the following form: -<tscreen> -<verb> -name_value="VARIABLE" -</verb> -</tscreen> -Here, <tt/VARIABLE/ is the environment variable's name and the absence -of an `<tt/=/' indicates that the variable should be removed. - -</itemize> - -<p> -In all cases <tt/PAM_SUCCESS/ indicates success. - -<sect2>Getting a Linux-PAM environment variable - -<p> -Synopsis: -<tscreen> -<verb> -extern const char *pam_getenv(pam_handle_t *pamh, const char *name); -</verb> -</tscreen> - -<p> -This function can be used to return the value of the given -variable. If the returned value is <tt/NULL/, the variable is not -known. - -<sect2>Listing the Linux-PAM environment - -<p> -Synopsis: -<tscreen> -<verb> -extern char * const *pam_getenvlist(pam_handle_t *pamh); -</verb> -</tscreen> - -<p> -This function returns a pointer to the entire <bf/Linux-PAM/ -environment array. At first sight the <em/type/ of the returned data -may appear a little confusing. It is basically a <em/read-only/ array -of character pointers, that lists the <tt/NULL/ terminated list of -environment variables set so far. - -<p> -Although, this is not a concern for the module programmer, we mention -here that an application should be careful to copy this entire array -before executing <tt/pam_end()/ otherwise all the variable information -will be lost. (There are functions in <tt/libpam_misc/ for this -purpose: <tt/pam_misc_copy_env()/ and <tt/pam_misc_drop_env()/.) - -<sect1>Other functions provided by <tt/libpam/ - -<sect2>Understanding errors - -<p> -<itemize> - -<item> -<tt>extern const char *pam_strerror(pam_handle_t *pamh, int errnum);</tt> - -<p> -This function returns some text describing the <bf/Linux-PAM/ error -associated with the argument <tt/errnum/. If the error is not -recognized <tt/``Unknown Linux-PAM error''/ is returned. - -</itemize> - -<sect2>Planning for delays - -<p> -<itemize> - -<item> -<tt>extern int pam_fail_delay(pam_handle_t *pamh, unsigned int -micro_sec)</tt> - -<p> -This function is offered by <bf/Linux-PAM/ to facilitate time delays -following a failed call to <tt/pam_authenticate()/ and before control -is returned to the application. When using this function the module -programmer should check if it is available with, -<tscreen> -<verb> -#ifdef PAM_FAIL_DELAY - .... -#endif /* PAM_FAIL_DELAY */ -</verb> -</tscreen> - -<p> -Generally, an application requests that a user is authenticated by -<bf/Linux-PAM/ through a call to <tt/pam_authenticate()/ or -<tt/pam_chauthtok()/. These functions call each of the <em/stacked/ -authentication modules listed in the <bf/Linux-PAM/ configuration -file. As directed by this file, one of more of the modules may fail -causing the <tt/pam_...()/ call to return an error. It is desirable -for there to also be a pause before the application continues. The -principal reason for such a delay is security: a delay acts to -discourage <em/brute force/ dictionary attacks primarily, but also -helps hinder <em/timed/ (cf. covert channel) attacks. - -<p> -The <tt/pam_fail_delay()/ function provides the mechanism by which an -application or module can suggest a minimum delay (of <tt/micro_sec/ -<em/micro-seconds/). <bf/Linux-PAM/ keeps a record of the longest time -requested with this function. Should <tt/pam_authenticate()/ fail, -the failing return to the application is delayed by an amount of time -randomly distributed (by up to 25%) about this longest value. - -<p> -Independent of success, the delay time is reset to its zero default -value when <bf/Linux-PAM/ returns control to the application. - -</itemize> - -<sect>What is expected of a module - -<p> -The module must supply a sub-set of the six functions listed -below. Together they define the function of a <bf/Linux-PAM -module/. Module developers are strongly urged to read the comments on -security that follow this list. - -<sect1> Overview - -<p> -The six module functions are grouped into four independent management -groups. These groups are as follows: <em/authentication/, -<em/account/, <em/session/ and <em/password/. To be properly defined, -a module must define all functions within at least one of these -groups. A single module may contain the necessary functions for -<em/all/ four groups. - -<sect2> Functional independence - -<p> -The independence of the four groups of service a module can offer -means that the module should allow for the possibility that any one of -these four services may legitimately be called in any order. Thus, the -module writer should consider the appropriateness of performing a -service without the prior success of some other part of the module. - -<p> -As an informative example, consider the possibility that an -application applies to change a user's authentication token, without -having first requested that <bf/Linux-PAM/ authenticate the user. In -some cases this may be deemed appropriate: when <tt/root/ wants to -change the authentication token of some lesser user. In other cases it -may not be appropriate: when <tt/joe/ maliciously wants to reset -<tt/alice/'s password; or when anyone other than the user themself -wishes to reset their <em/KERBEROS/ authentication token. A policy for -this action should be defined by any reasonable authentication scheme, -the module writer should consider this when implementing a given -module. - -<sect2> Minimizing administration problems - -<p> -To avoid system administration problems and the poor construction of a -<tt>/etc/pam.conf</tt> file, the module developer may define all -six of the following functions. For those functions that would not be -called, the module should return <tt/PAM_SERVICE_ERR/ and write an -appropriate message to the system log. When this action is deemed -inappropriate, the function would simply return <tt/PAM_IGNORE/. - -<sect2> Arguments supplied to the module - -<p> -The <tt/flags/ argument of each of the following functions can be -logically OR'd with <tt/PAM_SILENT/, which is used to inform the -module to not pass any <em/text/ (errors or warnings) to the -application. - -<p> -The <tt/argc/ and <tt/argv/ arguments are taken from the line -appropriate to this module---that is, with the <em/service_name/ -matching that of the application---in the configuration file (see the -<bf/Linux-PAM/ System Administrators' Guide). Together these two -parameters provide the number of arguments and an array of pointers to -the individual argument tokens. This will be familiar to C programmers -as the ubiquitous method of passing command arguments to the function -<tt/main()/. Note, however, that the first argument (<tt/argv[0]/) is -a true argument and <bf/not/ the name of the module. - -<sect1> Authentication management - -<p> -To be correctly initialized, <tt/PAM_SM_AUTH/ must be <tt/#define/'d -prior to including <tt><security/pam_modules.h></tt>. This will -ensure that the prototypes for static modules are properly declared. - -<p> -<itemize> - -<item> -<tt>PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, -int argc, const char **argv);</tt> - -<p> -This function performs the task of authenticating the user. - -<p> -The <tt/flags/ argument can be a logically OR'd with <tt/PAM_SILENT/ -and optionally take the following value: - -<p><descrip> -<tag><tt/PAM_DISALLOW_NULL_AUTHTOK/</tag> - return <tt/PAM_AUTH_ERR/ if the database of authentication -tokens for this authentication mechanism has a <tt/NULL/ entry for the -user. Without this flag, such a <tt/NULL/ token will lead to a success -without the user being prompted. -</descrip> - -<p> -Besides <tt/PAM_SUCCESS/ return values that can be sent by this -function are one of the following: - -<descrip> - -<tag><tt/PAM_AUTH_ERR/</tag> - The user was not authenticated -<tag><tt/PAM_CRED_INSUFFICIENT/</tag> - For some reason the application does not have sufficient -credentials to authenticate the user. -<tag><tt/PAM_AUTHINFO_UNAVAIL/</tag> - The modules were not able to access the authentication -information. This might be due to a network or hardware failure etc. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The supplied username is not known to the authentication -service -<tag><tt/PAM_MAXTRIES/</tag> - One or more of the authentication modules has reached its -limit of tries authenticating the user. Do not try again. - -</descrip> - -<item> -<tt>PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int -argc, const char **argv);</tt> - -<p> -This function performs the task of altering the credentials of the -user with respect to the corresponding authorization -scheme. Generally, an authentication module may have access to more -information about a user than their authentication token. This -function is used to make such information available to the -application. It should only be called <em/after/ the user has been -authenticated but before a session has been established. - -<p> -Permitted flags, one of which, may be logically OR'd with -<tt/PAM_SILENT/ are, - -<p><descrip> -<tag><tt/PAM_ESTABLISH_CRED/</tag> - Set the credentials for the authentication service, -<tag><tt/PAM_DELETE_CRED/</tag> - Delete the credentials associated with the authentication service, -<tag><tt/PAM_REINITIALIZE_CRED/</tag> - Reinitialize the user credentials, and -<tag><tt/PAM_REFRESH_CRED/</tag> - Extend the lifetime of the user credentials. -</descrip> - -<p> -Prior to <bf/Linux-PAM-0.75/, and due to a deficiency with the way the -<tt/auth/ stack was handled in the case of the setcred stack being -processed, the module was required to attempt to return the same error -code as <tt/pam_sm_authenticate/ did. This was necessary to preserve -the logic followed by libpam as it executes the stack of -<em/authentication/ modules, when the application called either -<tt/pam_authenticate()/ or <tt/pam_setcred()/. Failing to do this, -led to confusion on the part of the System Administrator. - -<p> -For <bf/Linux-PAM-0.75/ and later, libpam handles the credential stack -much more sanely. The way the <tt/auth/ stack is navigated in order to -evaluate the <tt/pam_setcred()/ function call, independent of the -<tt/pam_sm_setcred()/ return codes, is exactly the same way that it -was navigated when evaluating the <tt/pam_authenticate()/ library -call. Typically, if a stack entry was ignored in evaluating -<tt/pam_authenticate()/, it will be ignored when libpam evaluates the -<tt/pam_setcred()/ function call. Otherwise, the return codes from -each module specific <tt/pam_sm_setcred()/ call are treated as -<tt/required/. - -<p> -Besides <tt/PAM_SUCCESS/, the module may return one of the following -errors: - -<p><descrip> -<tag><tt/PAM_CRED_UNAVAIL/</tag> - This module cannot retrieve the user's credentials. -<tag><tt/PAM_CRED_EXPIRED/</tag> - The user's credentials have expired. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to this authentication module. -<tag><tt/PAM_CRED_ERR/</tag> - This module was unable to set the credentials of the user. -</descrip> - -<p> -these, non-<tt/PAM_SUCCESS/, return values will typically lead to the -credential stack <em/failing/. The first such error will dominate in -the return value of <tt/pam_setcred()/. - -</itemize> - -<sect1> Account management - -<p> -To be correctly initialized, <tt/PAM_SM_ACCOUNT/ must be -<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. -This will ensure that the prototype for a static module is properly -declared. - -<p> -<itemize> - -<item> -<tt>PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int -argc, const char **argv);</tt> - -<p> -This function performs the task of establishing whether the user is -permitted to gain access at this time. It should be understood that -the user has previously been validated by an authentication -module. This function checks for other things. Such things might be: -the time of day or the date, the terminal line, remote -hostname, etc. . - -<p> -This function may also determine things like the expiration on -passwords, and respond that the user change it before continuing. - -<p> -Valid flags, which may be logically OR'd with <tt/PAM_SILENT/, are the -same as those applicable to the <tt/flags/ argument of -<tt/pam_sm_authenticate/. - -<p> -This function may return one of the following errors, - -<descrip> - -<tag><tt/PAM_ACCT_EXPIRED/</tag> - The user is no longer permitted access to the system. -<tag><tt/PAM_AUTH_ERR/</tag> - There was an authentication error. -<tag><tt/PAM_AUTHTOKEN_REQD/</tag> - The user's authentication token has expired. Before calling -this function again the application will arrange for a new one to be -given. This will likely result in a call to <tt/pam_sm_chauthtok()/. -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to the module's account management -component. - -</descrip> - -</itemize> - -<sect1> Session management - -<p> -To be correctly initialized, <tt/PAM_SM_SESSION/ must be -<tt/#define/'d prior to including -<tt><security/pam_modules.h></tt>. This will ensure that the -prototypes for static modules are properly declared. - -<p> -The following two functions are defined to handle the -initialization/termination of a session. For example, at the beginning -of a session the module may wish to log a message with the system -regarding the user. Similarly, at the end of the session the module -would inform the system that the user's session has ended. - -<p> -It should be possible for sessions to be opened by one application and -closed by another. This either requires that the module uses only -information obtained from <tt/pam_get_item()/, or that information -regarding the session is stored in some way by the operating system -(in a file for example). - -<p> -<itemize> - -<item> -<tt>PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int -argc, const char **argv);</tt> - -<p> -This function is called to commence a session. The only valid, but -optional, flag is <tt/PAM_SILENT/. - -<p> -As a return value, <tt/PAM_SUCCESS/ signals success and -<tt/PAM_SESSION_ERR/ failure. - -<item> -<tt>PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int -argc, const char **argv);</tt> - -<p> -This function is called to terminate a session. The only valid, but -optional, flag is <tt/PAM_SILENT/. - -<p> -As a return value, <tt/PAM_SUCCESS/ signals success and -<tt/PAM_SESSION_ERR/ failure. - -</itemize> - -<sect1> Password management - -<p> -To be correctly initialized, <tt/PAM_SM_PASSWORD/ must be -<tt/#define/'d prior to including <tt><security/pam_modules.h></tt>. -This will ensure that the prototype for a static module is properly -declared. - -<p> -<itemize> - -<item> -<tt>PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int -argc, const char **argv);</tt> - -<p> -This function is used to (re-)set the authentication token of the -user. A valid flag, which may be logically OR'd with <tt/PAM_SILENT/, -can be built from the following list, - -<descrip> -<tag><tt/PAM_CHANGE_EXPIRED_AUTHTOK/</tag> - This argument indicates to the module that the users -authentication token (password) should only be changed if it has -expired. This flag is optional and <em/must/ be combined with one of -the following two flags. Note, however, the following two options are -<em/mutually exclusive/. - -<tag><tt/PAM_PRELIM_CHECK/</tag> - This indicates that the modules are being probed as to their -ready status for altering the user's authentication token. If the -module requires access to another system over some network it should -attempt to verify it can connect to this system on receiving this -flag. If a module cannot establish it is ready to update the user's -authentication token it should return <tt/PAM_TRY_AGAIN/, this -information will be passed back to the application. - -<tag><tt/PAM_UPDATE_AUTHTOK/</tag> - This informs the module that this is the call it should change -the authorization tokens. If the flag is logically OR'd with -<tt/PAM_CHANGE_EXPIRED_AUTHTOK/, the token is only changed if it has -actually expired. - -</descrip> - -<p> -Note, the <bf/Linux-PAM/ library calls this function twice in -succession. The first time with <tt/PAM_PRELIM_CHECK/ and then, if the -module does not return <tt/PAM_TRY_AGAIN/, subsequently with -<tt/PAM_UPDATE_AUTHTOK/. It is only on the second call that the -authorization token is (possibly) changed. - -<p> -<tt/PAM_SUCCESS/ is the only successful return value, valid -error-returns are: - -<descrip> -<tag><tt/PAM_AUTHTOK_ERR/</tag> - The module was unable to obtain the new authentication token. - -<tag><tt/PAM_AUTHTOK_RECOVERY_ERR/</tag> - The module was unable to obtain the old authentication token. - -<tag><tt/PAM_AUTHTOK_LOCK_BUSY/</tag> - Cannot change the authentication token since it is currently -locked. - -<tag><tt/PAM_AUTHTOK_DISABLE_AGING/</tag> - Authentication token aging has been disabled. - -<tag><tt/PAM_PERM_DENIED/</tag> - Permission denied. - -<tag><tt/PAM_TRY_AGAIN/</tag> - Preliminary check was unsuccessful. Signals an immediate return -to the application is desired. - -<tag><tt/PAM_USER_UNKNOWN/</tag> - The user is not known to the authentication token changing -service. - -</descrip> - -</itemize> - -<sect>Generic optional arguments - -<p> -Here we list the generic arguments that all modules can expect to -be passed. They are not mandatory, and their absence should be -accepted without comment by the module. - -<p> -<descrip> -<tag><tt/debug/</tag> - -Use the <tt/syslog(3)/ call to log debugging information to the system -log files. - -<tag><tt/no_warn/</tag> - -Instruct module to not give warning messages to the application. - -<tag><tt/use_first_pass/</tag> - -The module should not prompt the user for a password. Instead, it -should obtain the previously typed password (by a call to -<tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ item), and use that. If -that doesn't work, then the user will not be authenticated. (This -option is intended for <tt/auth/ and <tt/passwd/ modules only). - -<tag><tt/try_first_pass/</tag> - -The module should attempt authentication with the previously typed -password (by a call to <tt/pam_get_item()/ for the <tt/PAM_AUTHTOK/ -item). If that doesn't work, then the user is prompted for a -password. (This option is intended for <tt/auth/ modules only). - -<tag><tt/use_mapped_pass/</tag> - -<bf/WARNING:/ coding this functionality may cause the module writer to -break <em/local/ encryption laws. For example, in the U.S. there are -restrictions on the export computer code that is capable of strong -encryption. It has not been established whether this option is -affected by this law, but one might reasonably assume that it does -until told otherwise. For this reason, this option is not supported -by any of the modules distributed with <bf/Linux-PAM/. - -The intended function of this argument, however, is that the module -should take the existing authentication token from a previously -invoked module and use it as a key to retrieve the authentication -token for this module. For example, the module might create a strong -hash of the <tt/PAM_AUTHTOK/ item (established by a previously -executed module). Then, with logical-exclusive-or, use the result as a -<em/key/ to safely store/retrieve the authentication token for this -module in/from a local file <em/etc/. . - -<tag><tt/expose_account/</tag> - -<p> -In general the leakage of some information about user accounts is not -a secure policy for modules to adopt. Sometimes information such as -users names or home directories, or preferred shell, can be used to -attack a user's account. In some circumstances, however, this sort of -information is not deemed a threat: displaying a user's full name when -asking them for a password in a secured environment could also be -called being 'friendly'. The <tt/expose_account/ argument is a -standard module argument to encourage a module to be less discrete -about account information as it is deemed appropriate by the local -administrator. - -</descrip> - -<sect>Programming notes - -<p> -Here we collect some pointers for the module writer to bear in mind -when writing/developing a <bf/Linux-PAM/ compatible module. - -<sect1>Security issues for module creation - -<sect2>Sufficient resources - -<p> -Care should be taken to ensure that the proper execution of a module -is not compromised by a lack of system resources. If a module is -unable to open sufficient files to perform its task, it should fail -gracefully, or request additional resources. Specifically, the -quantities manipulated by the <tt/setrlimit(2)/ family of commands -should be taken into consideration. - -<sect2>Who's who? - -<p> -Generally, the module may wish to establish the identity of the user -requesting a service. This may not be the same as the username -returned by <tt/pam_get_user()/. Indeed, that is only going to be the -name of the user under whose identity the service will be given. This -is not necessarily the user that requests the service. - -<p> -In other words, user X runs a program that is setuid-Y, it grants the -user to have the permissions of Z. A specific example of this sort of -service request is the <em/su/ program: user <tt/joe/ executes -<em/su/ to become the user <em/jane/. In this situation X=<tt/joe/, -Y=<tt/root/ and Z=<tt/jane/. Clearly, it is important that the module -does not confuse these different users and grant an inappropriate -level of privilege. - -<p> -The following is the convention to be adhered to when juggling -user-identities. - -<p> -<itemize> -<item>X, the identity of the user invoking the service request. -This is the user identifier; returned by the function <tt/getuid(2)/. - -<item>Y, the privileged identity of the application used to grant the -requested service. This is the <em/effective/ user identifier; -returned by the function <tt/geteuid(2)/. - -<item>Z, the user under whose identity the service will be granted. -This is the username returned by <tt/pam_get_user(2)/ and also stored -in the <bf/Linux-PAM/ item, <tt/PAM_USER/. - -<item><bf/Linux-PAM/ has a place for an additional user identity that -a module may care to make use of. This is the <tt/PAM_RUSER/ item. -Generally, network sensitive modules/applications may wish to set/read -this item to establish the identity of the user requesting a service -from a remote location. - -</itemize> - -<p> -Note, if a module wishes to modify the identity of either the <tt/uid/ -or <tt/euid/ of the running process, it should take care to restore -the original values prior to returning control to the <bf/Linux-PAM/ -library. - -<sect2>Using the conversation function -<p> -Prior to calling the conversation function, the module should reset -the contents of the pointer that will return the applications -response. This is a good idea since the application may fail to fill -the pointer and the module should be in a position to notice! - -<p> -The module should be prepared for a failure from the conversation. The -generic error would be <tt/PAM_CONV_ERR/, but anything other than -<tt/PAM_SUCCESS/ should be treated as indicating failure. - -<sect2>Authentication tokens - -<p> -To ensure that the authentication tokens are not left lying around the -items, <tt/PAM_AUTHTOK/ and <tt/PAM_OLDAUTHTOK/, are not available to -the application: they are defined in -<tt><security/pam_modules.h></tt>. This is ostensibly for -security reasons, but a maliciously programmed application will always -have access to all memory of the process, so it is only superficially -enforced. As a general rule the module should overwrite -authentication tokens as soon as they are no longer needed. -Especially before <tt/free()/'ing them. The <bf/Linux-PAM/ library is -required to do this when either of these authentication token items -are (re)set. - -<p> -Not to dwell too little on this concern; should the module store the -authentication tokens either as (automatic) function variables or -using <tt/pam_[gs]et_data()/ the associated memory should be -over-written explicitly before it is released. In the case of the -latter storage mechanism, the associated <tt/cleanup()/ function -should explicitly overwrite the <tt/*data/ before <tt/free()/'ing it: -for example, - -<tscreen> -<verb> -/* - * An example cleanup() function for releasing memory that was used to - * store a password. - */ - -int cleanup(pam_handle_t *pamh, void *data, int error_status) -{ - char *xx; - - if ((xx = data)) { - while (*xx) - *xx++ = '\0'; - free(data); - } - return PAM_SUCCESS; -} -</verb> -</tscreen> - -<sect1>Use of <tt/syslog(3)/ - -<p> -Only rarely should error information be directed to the user. Usually, -this is to be limited to ``<em/sorry you cannot login now/'' type -messages. Information concerning errors in the configuration file, -<tt>/etc/pam.conf</tt>, or due to some system failure encountered by -the module, should be written to <tt/syslog(3)/ with -<em/facility-type/ <tt/LOG_AUTHPRIV/. - -<p> -With a few exceptions, the level of logging is, at the discretion of -the module developer. Here is the recommended usage of different -logging levels: - -<p> -<itemize> - -<item> -As a general rule, errors encountered by a module should be logged at -the <tt/LOG_ERR/ level. However, information regarding an unrecognized -argument, passed to a module from an entry in the -<tt>/etc/pam.conf</tt> file, is <bf/required/ to be logged at the -<tt/LOG_ERR/ level. - -<item> -Debugging information, as activated by the <tt/debug/ argument to the -module in <tt>/etc/pam.conf</tt>, should be logged at the -<tt/LOG_DEBUG/ level. - -<item> -If a module discovers that its personal configuration file or some -system file it uses for information is corrupted or somehow unusable, -it should indicate this by logging messages at level, <tt/LOG_ALERT/. - -<item> -Shortages of system resources, such as a failure to manipulate a file -or <tt/malloc()/ failures should be logged at level <tt/LOG_CRIT/. - -<item> -Authentication failures, associated with an incorrectly typed password -should be logged at level, <tt/LOG_NOTICE/. - -</itemize> - -<sect1> Modules that require system libraries - -<p> -Writing a module is much like writing an application. You have to -provide the "conventional hooks" for it to work correctly, like -<tt>pam_sm_authenticate()</tt> etc., which would correspond to the -<tt/main()/ function in a normal function. - -<p> -Typically, the author may want to link against some standard system -libraries. As when one compiles a normal program, this can be done for -modules too: you simply append the <tt>-l</tt><em>XXX</em> arguments -for the desired libraries when you create the shared module object. To -make sure a module is linked to the <tt>lib<em>whatever</em>.so</tt> -library when it is <tt>dlopen()</tt>ed, try: -<tscreen> -<verb> -% gcc -shared -Xlinker -x -o pam_module.so pam_module.o -lwhatever -</verb> -</tscreen> - -<sect1> Added requirements for <em/statically/ loaded modules. - -<!-- - Copyright (C) Michael K. Johnson 1996. - Last modified: AGM 1996/5/31. - --> - -<p> -Modules may be statically linked into libpam. This should be true of -all the modules distributed with the basic <bf/Linux-PAM/ -distribution. To be statically linked, a module needs to export -information about the functions it contains in a manner that does not -clash with other modules. - -The extra code necessary to build a static module should be delimited -with <tt/#ifdef PAM_STATIC/ and <tt/#endif/. The static code should do -the following: -<itemize> -<item> Define a single structure, <tt/struct pam_module/, called -<tt>_pam_<it>modname</it>_modstruct</tt>, where -<tt><it>modname</it></tt> is the name of the module <bf/as used in the -filesystem/ but without the leading directory name (generally -<tt>/usr/lib/security/</tt> or the suffix (generally <tt/.so/). - -</itemize> - -<p> -As a simple example, consider the following module code which defines -a module that can be compiled to be <em/static/ or <em/dynamic/: - -<p> -<tscreen> -<verb> -#include <stdio.h> /* for NULL define */ - -#define PAM_SM_PASSWORD /* the only pam_sm_... function declared */ -#include <security/pam_modules.h> - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC /* for the case that this module is static */ - -struct pam_module _pam_modname_modstruct = { /* static module data */ - "pam_modname", - NULL, - NULL, - NULL, - NULL, - NULL, - pam_sm_chauthtok, -}; - -#endif /* end PAM_STATIC */ -</verb> -</tscreen> - -<p> -To be linked with <em/libpam/, staticly-linked modules must be built -from within the <tt>Linux-PAM-X.YY/modules/</tt> subdirectory of the -<bf/Linux-PAM/ source directory as part of a normal build of the -<bf/Linux-PAM/ system. - -The <em/Makefile/, for the module in question, must execute the -<tt/register_static/ shell script that is located in the -<tt>Linux-PAM-X.YY/modules/</tt> subdirectory. This is to ensure that -the module is properly registered with <em/libpam/. - -The <bf/two/ manditory arguments to <tt/register_static/ are the -title, and the pathname of the object file containing the module's -code. The pathname is specified relative to the -<tt>Linux-PAM-X.YY/modules</tt> directory. The pathname may be an -empty string---this is for the case that a single object file needs to -register more than one <tt/struct pam_module/. In such a case, exactly -one call to <tt/register_static/ must indicate the object file. - -<p> -Here is an example; a line in the <em/Makefile/ might look like this: -<tscreen> -<verb> -register: -ifdef STATIC - (cd ..; ./register_static pam_modname pam_modname/pam_modname.o) -endif -</verb> -</tscreen> - -For some further examples, see the <tt>modules</tt> subdirectory of -the current <bf/Linux-PAM/ distribution. - -<sect>An example module file - -<p> -At some point, we may include a fully commented example of a module in -this document. For now, we point the reader to these two locations in -the public CVS repository: -<itemize> -<item> A module that always succeeds: <tt><htmlurl -url="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_permit/" -name="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_permit/" -></tt> -<item> A module that always fails: <tt><htmlurl -url="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_deny/" -name="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/modules/pam_deny/" -></tt> -</itemize> - -<sect>Files - -<p><descrip> - -<tag><tt>/usr/lib/libpam.so.*</tt></tag> - -the shared library providing applications with access to -<bf/Linux-PAM/. - -<tag><tt>/etc/pam.conf</tt></tag> - -the <bf/Linux-PAM/ configuration file. - -<tag><tt>/usr/lib/security/pam_*.so</tt></tag> - -the primary location for <bf/Linux-PAM/ dynamically loadable object -files; the modules. - -</descrip> - -<sect>See also - -<p><itemize> -<item>The <bf/Linux-PAM/ System Administrators' Guide. -<item>The <bf/Linux-PAM/ Application Writers' Guide. -<item> -V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH PLUGGABLE -AUTHENTICATION MODULES'', Open Software Foundation Request For -Comments 86.0, October 1995. -</itemize> - -<sect>Notes - -<p> -I intend to put development comments here... like ``at the moment -this isn't actually supported''. At release time what ever is in -this section will be placed in the Bugs section below! :) - -<p> -<itemize> -<item> -Perhaps we should keep a registry of data-names as used by -<tt/pam_[gs]et_data()/ so there are no unintentional problems due to -conflicts? - -<item> -<tt/pam_strerror()/ should be internationalized.... - -<item> -There has been some debate about whether <tt/initgroups()/ should be -in an application or in a module. It was settled by Sun who stated -that initgroups is an action of the <em/application/. The modules are -permitted to add additional groups, however. - -<item> -Refinements/futher suggestions to <tt/syslog(3)/ usage by modules are -needed. - -</itemize> - -<sect>Author/acknowledgments - -<p> -This document was written by Andrew G. Morgan -(<tt/morgan@kernel.org/) with many contributions from -<!-- insert credits here --> -<!-- - an sgml list of people to credit for their contributions to Linux-PAM - $Id$ - --> -Chris Adams, -Peter Allgeyer, -Tim Baverstock, -Tim Berger, -Craig S. Bell, -Derrick J. Brashear, -Ben Buxton, -Seth Chaiklin, -Oliver Crow, -Chris Dent, -Marc Ewing, -Cristian Gafton, -Emmanuel Galanos, -Brad M. Garcia, -Eric Hester, -Roger Hu, -Eric Jacksch, -Michael K. Johnson, -David Kinchlea, -Olaf Kirch, -Marcin Korzonek, -Stephen Langasek, -Nicolai Langfeldt, -Elliot Lee, -Luke Kenneth Casson Leighton, -Al Longyear, -Ingo Luetkebohle, -Marek Michalkiewicz, -Robert Milkowski, -Aleph One, -Martin Pool, -Sean Reifschneider, -Jan Rekorajski, -Erik Troan, -Theodore Ts'o, -Jeff Uphoff, -Myles Uyema, -Savochkin Andrey Vladimirovich, -Ronald Wahl, -David Wood, -John Wilmes, -Joseph S. D. Yao -and -Alex O. Yuriev. - -<p> -Thanks are also due to Sun Microsystems, especially to Vipin Samar and -Charlie Lai for their advice. At an early stage in the development of -<bf/Linux-PAM/, Sun graciously made the documentation for their -implementation of PAM available. This act greatly accelerated the -development of <bf/Linux-PAM/. - -<sect>Bugs/omissions - -<p> -Few PAM modules currently exist. Few PAM-aware applications exist. -This document is hopelessly unfinished. Only a partial list of people is -credited for all the good work they have done. - -<sect>Copyright information for this document - -<p> -Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. -<newline> -Email: <tt><morgan@kernel.org></tt> - -<p> -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -<p> -<itemize> - -<item> -1. Redistributions of source code must retain the above copyright - notice, and the entire permission notice in its entirety, - including the disclaimer of warranties. - -<item> -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -<item> -3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -</itemize> - -<p> -<bf/Alternatively/, this product may be distributed under the terms of -the GNU General Public License (GPL), in which case the provisions of -the GNU GPL are required <bf/instead of/ the above restrictions. -(This clause is necessary due to a potential bad interaction between -the GNU GPL and the restrictions contained in a BSD-style copyright.) - -<p> -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -<p> -<tt>$Id$</tt> - -</article> diff --git a/doc/pam_source.sgml b/doc/pam_source.sgml deleted file mode 100644 index 2dd5783e..00000000 --- a/doc/pam_source.sgml +++ /dev/null @@ -1,1160 +0,0 @@ -<!doctype linuxdoc system> - -<!-- - - $Id$ - - Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. - -Redistribution and use in source (sgml) and binary (derived) forms, -with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, and the entire permission notice in its entirety, - including the disclaimer of warranties. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -ALTERNATIVELY, this product may be distributed under the terms of the -GNU General Public License, in which case the provisions of the GNU -GPL are required INSTEAD OF the above restrictions. (This clause is -necessary due to a potential bad interaction between the GNU GPL and -the restrictions contained in a BSD-style copyright.) - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - - --> - -<article> - -<title>The Linux-PAM System Administrators' Guide -<author>Andrew G. Morgan, <tt>morgan@kernel.org</tt> -<date>DRAFT v0.76 2002/06/26 -<abstract> -This manual documents what a system-administrator needs to know about -the <bf>Linux-PAM</bf> library. It covers the correct syntax of the -PAM configuration file and discusses strategies for maintaining a -secure system. -</abstract> - -<!-- Table of contents --> -<toc> - -<!-- Begin the document --> - -<sect>Introduction - -<p><bf/Linux-PAM/ (Pluggable Authentication Modules for Linux) is a -suite of shared libraries that enable the local system administrator -to choose how applications authenticate users. - -<p>In other words, without (rewriting and) recompiling a PAM-aware -application, it is possible to switch between the authentication -mechanism(s) it uses. Indeed, one may entirely upgrade the local -authentication system without touching the applications themselves. - -<p>Historically an application that has required a given user to be -authenticated, has had to be compiled to use a specific authentication -mechanism. For example, in the case of traditional UN*X systems, the -identity of the user is verified by the user entering a correct -password. This password, after being prefixed by a two character -``salt'', is encrypted (with crypt(3)). The user is then authenticated -if this encrypted password is identical to the second field of the -user's entry in the system password database (the <tt>/etc/passwd</tt> -file). On such systems, most if not all forms of privileges are -granted based on this single authentication scheme. Privilege comes in -the form of a personal user-identifier (<tt/uid/) and membership of -various groups. Services and applications are available based on the -personal and group identity of the user. Traditionally, group -membership has been assigned based on entries in the -<tt>/etc/group</tt> file. - -<p> -Unfortunately, increases in the speed of computers and the -widespread introduction of network based computing, have made once -secure authentication mechanisms, such as this, vulnerable to -attack. In the light of such realities, new methods of authentication -are continuously being developed. - -<p> -It is the purpose of the <bf/Linux-PAM/ project to separate the -development of privilege granting software from the development of -secure and appropriate authentication schemes. This is accomplished -by providing a library of functions that an application may use to -request that a user be authenticated. This PAM library is configured -locally with a system file, <tt>/etc/pam.conf</tt> (or a series of -configuration files located in <tt>/etc/pam.d/</tt>) to authenticate a -user request via the locally available authentication modules. The -modules themselves will usually be located in the directory -<tt>/lib/security</tt> and take the form of dynamically loadable -object files (see <tt/dlopen(3)/). - -<sect>Some comments on the text<label id="text-conventions"> - -<p> -Before proceeding to read the rest of this document, it should be -noted that the text assumes that certain files are placed in certain -directories. Where they have been specified, the conventions we adopt -here for locating these files are those of the relevant RFC (RFC-86.0, -see <ref id="see-also-sec" name="bibliography">). If you are using a -distribution of Linux (or some other operating system) that supports -PAM but chooses to distribute these files in a diferent way you should -be careful when copying examples directly from the text. - -<p> -As an example of the above, where it is explicit, the text assumes -that PAM loadable object files (the <em/modules/) are to be located in -the following directory: <tt>/lib/security/</tt>. This is generally -the location that seems to be compatible with the Linux File System -Standard (the FSSTND). On Solaris, which has its own licensed version -of PAM, and some other implementations of UN*X, these files can be -found in <tt>/usr/lib/security</tt>. Please be careful to perform the -necessary transcription when using the examples from the text. - -<sect>Overview<label id="overview-section"> - -<p> -For the uninitiated, we begin by considering an example. We take an -application that grants some service to users; <em/login/ is one such -program. <em/Login/ does two things, it first establishes that the -requesting user is whom they claim to be and second provides them with -the requested service: in the case of <em/login/ the service is a -command shell (<em>bash, tcsh, zsh, etc.</em>) running with the -identity of the user. - -<p> -Traditionally, the former step is achieved by the <em/login/ -application prompting the user for a password and then verifying that -it agrees with that located on the system; hence verifying that -as far as the system is concerned the user is who they claim to be. -This is the task that is delegated to <bf/Linux-PAM/. - -<p> -From the perspective of the application programmer (in this case the -person that wrote the <em/login/ application), <bf/Linux-PAM/ takes -care of this authentication task -- verifying the identity of the user. - -<p> -The flexibility of <bf/Linux-PAM/ is that <em/you/, the system -administrator, have the freedom to stipulate which authentication -scheme is to be used. You have the freedom to set the scheme for -any/all PAM-aware applications on your Linux system. That is, you can -authenticate from anything as naive as <em/simple trust/ -(<tt/pam_permit/) to something as paranoid as a combination of a -retinal scan, a voice print and a one-time password! - -<p> -To illustrate the flexibility you face, consider the following -situation: a system administrator (parent) wishes to improve the -mathematical ability of her users (children). She can configure their -favorite ``Shoot 'em up game'' (PAM-aware of course) to authenticate -them with a request for the product of a couple of random numbers less -than 12. It is clear that if the game is any good they will soon learn -their <em/multiplication tables/. As they mature, the authentication -can be upgraded to include (long) division! - -<p> -<bf/Linux-PAM/ deals with four separate types of (management) -task. These are: <em/authentication management/; <em/account -management/; <em/session management/; and <em/password management/. -The association of the preferred management scheme with the behavior -of an application is made with entries in the relevant <bf/Linux-PAM/ -configuration file. The management functions are performed by -<em/modules/ specified in the configuration file. The syntax for this -file is discussed in the section <ref id="configuration" -name="below">. - -<p> -Here is a figure that describes the overall organization of -<bf/Linux-PAM/. -<tscreen> -<verb> - +----------------+ - | application: X | - +----------------+ / +----------+ +================+ - | authentication-[---->--\--] Linux- |--<--| PAM config file| - | + [----<--/--] PAM | |================| - |[conversation()][--+ \ | | | X auth .. a.so | - +----------------+ | / +-n--n-----+ | X auth .. b.so | - | | | __| | | _____/ - | service user | A | | |____,-----' - | | | V A - +----------------+ +------|-----|---------+ -----+------+ - +---u-----u----+ | | | - | auth.... |--[ a ]--[ b ]--[ c ] - +--------------+ - | acct.... |--[ b ]--[ d ] - +--------------+ - | password |--[ b ]--[ c ] - +--------------+ - | session |--[ e ]--[ c ] - +--------------+ -</verb> -</tscreen> -By way of explanation, the left of the figure represents the -application; application X. Such an application interfaces with the -<bf/Linux-PAM/ library and knows none of the specifics of its -configured authentication method. The <bf/Linux-PAM/ library (in the -center) consults the contents of the PAM configuration file and loads -the modules that are appropriate for application-X. These modules fall -into one of four management groups (lower-center) and are stacked in -the order they appear in the configuration file. These modules, when -called by <bf/Linux-PAM/, perform the various authentication tasks for -the application. Textual information, required from/or offered to the -user, can be exchanged through the use of the application-supplied -<em/conversation/ function. - -<sect1>Getting started - -<p> -The following text was contributed by Seth Chaiklin: -<tscreen> -<verb> -To this point, we have described how PAM should work in an -ideal world, in which all applications are coded properly. -However, at the present time (October 1998), this is far -from the case. Therefore, here are some practical considerations -in trying to use PAM in your system. - -Why bother, is it really worth all the trouble? - -If you running Linux as a single user system, or in an -environment where all the users are trusted, then there -is no real advantage for using PAM. -</verb> -</tscreen> - -<p> -<BF>Ed:</BF> there is actually an advantage since you can <em/dummy -down/ the authentication to the point where you don't have -any... Almost like Win95. -<p> -In a networked environment, it is clear that you need to think a -little more about how users etc., are authenticated:] - -<p> -<tscreen> -<verb> -If you are running Linux as a server, where several different -services are being provided (e.g., WWW with areas restricted by -password control, PPP), then there can be some real and interesting -value for PAM. In particular, through the use of modules, PAM can -enable a program to search through several different password -databases, even if that program is not explicitly coded for -that particular database. Here are some examples of the possibilities -that this enables. - - o Apache has a module that provides PAM services. Now - authentication - to use particular directories can be conducted by PAM, which - means that the range of modules that are available to PAM can - be used, including RADIUS, NIS, NCP (which means that Novell - password databases can be used). - - o pppd has a PAMified version (available from RedHat) Now it is - possible to use a series of databases to authenticate ppp users. - In addition to the normal Linux-based password databases (such - as /etc/passwd and /etc/shadow), you can use PAM modules to - authenticate against Novell password databases or NT-based - password databases. - - o The preceding two examples can be combined. Imagaine that the - persons in your office/department are already registered with a - username and password in a Novell or NT LAN. If you wanted to - use this database on your Linux server (for PPP access, for - web access, or even for normal shell access), you can use PAM - to authenticate against this existing database, rather than - maintain a separate database on both Linux and the LAN server. - - -Can I use PAM for any program that requires authentication? - -Yes and no. Yes, if you have access to the source code, and can -add the appropriate PAM functions. No, if you do not have access -to the source code, and the binary does not have the PAM functions -included. - -In other words, if a program is going to use PAM, then it has to -have PAM functions explicitly coded into the program. If they -are not, then it is not possible to use PAM. - -How can I tell whether a program has PAM coded into it or not? - -A quick-and-dirty (but not always reliable) method is to ldd -<programname> -If libpam and libpam_misc are not among the libraries that the program -uses, then it is not going to work with PAM. However, it is possible -that the libraries are included, but there are still problems, because -the PAM coding in the program does not work as it should. So a -more reliable method is to make the follow tests. - -In the /etc/pam.d directory, one needs to make a configuration file -for the program that one wants to run. The exact name of the -configuration -file is hard-coded into the program. Usually, it is the same name as -the -program, but not always. For sake of illustration, let's assume that -the program is named "pamprog" and the name of the configuration file -is /etc/pam.d/pamprog. - -In the /etc/pam.d/pamprog but the following two lines: - -auth required pam_permit.so -auth required pam_warn.so - - -Now try to use pamprog. The first line in the configuration file -says that all users are permitted. The second line will write a -warning to your syslog file (or whether you syslog is writing - -messages). If this test succeeds, then you know that you have -a program that can understand pam, and you can start the more -interesting work of deciding how to stack modules in your -/etc/pam.d/pamprog file. -</verb> -</tscreen> - -<sect>The Linux-PAM configuration file -<label id="configuration"> - -<p> -<bf/Linux-PAM/ is designed to provide the system administrator with a -great deal of flexibility in configuring the privilege granting -applications of their system. The local configuration of those aspects -of system security controlled by <tt/Linux-PAM/ is contained in one of -two places: either the single system file, <tt>/etc/pam.conf</tt>; or -the <tt>/etc/pam.d/</tt> directory. In this section we discuss the -correct syntax of and generic options respected by entries to these -files. - -<sect1>Configuration file syntax - -<p> -The reader should note that the <bf/Linux-PAM/ specific tokens in this -file are case <em/insensitive/. The module paths, however, are case -sensitive since they indicate a file's <em/name/ and reflect the case -dependence of typical Linux file-systems. The case-sensitivity of the -arguments to any given module is defined for each module in turn. - -<p> -In addition to the lines described below, there are two <em/special/ -characters provided for the convenience of the system administrator: -comments are preceded by a `<tt/#/' and extend to the -next end-of-line; also, module specification lines may be extended -with a `<tt/\/' escaped newline. - -<p> -A general configuration line of the <tt>/etc/pam.conf</tt> file has -the following form: -<tscreen> -<verb> -service-name module-type control-flag module-path args -</verb> -</tscreen> -Below, we explain the meaning of each of these tokens. The second (and -more recently adopted) way of configuring <bf/Linux-PAM/ is via the -contents of the <tt>/etc/pam.d/</tt> directory. Once we have explained -the meaning of the above tokens, we will describe this method. - -<p> -<descrip> -<tag><tt/service-name/</tag> -The name of the service associated with this entry. Frequently the -service name is the conventional name of the given application. For -example, `<tt/ftpd/', `<tt/rlogind/' and `<tt/su/', <em/etc./ . - -<p> -There is a special <tt/service-name/, reserved for defining a default -authentication mechanism. It has the name `<tt/OTHER/' and may be -specified in either lower or upper case characters. Note, when there -is a module specified for a named service, the `<tt/OTHER/' entries -are ignored. - -<tag><tt/module-type/</tag> -One of (currently) four types of module. The four types are as -follows: -<itemize> -<item> <tt/auth/; this module type provides two aspects of -authenticating the user. Firstly, it establishes that the user is who -they claim to be, by instructing the application to prompt the user -for a password or other means of identification. Secondly, the module -can grant <tt/group/ membership (independently of the -<tt>/etc/groups</tt> file discussed above) or other privileges through -its <em/credential/ granting properties. - -<item> <tt/account/; this module performs non-authentication based -account management. It is typically used to restrict/permit access to -a service based on the time of day, currently available system -resources (maximum number of users) or perhaps the location of the -applicant user---`<tt/root/' login only on the console. - -<item> <tt/session/; primarily, this module is associated with doing -things that need to be done for the user before/after they can be -given service. Such things include the logging of information -concerning the opening/closing of some data exchange with a user, -mounting directories, etc. . - -<item> <tt/password/; this last module type is required for updating the -authentication token associated with the user. Typically, there is one -module for each `challenge/response' based authentication (<tt/auth/) -module-type. - -</itemize> - -<tag><tt/control-flag/</tag> - -The control-flag is used to indicate how the PAM library will react to -the success or failure of the module it is associated with. Since -modules can be <em/stacked/ (modules of the same type execute in -series, one after another), the control-flags determine the relative -importance of each module. The application is not made aware of the -individual success or failure of modules listed in the -`<tt>/etc/pam.conf</tt>' file. Instead, it receives a summary -<em/success/ or <em/fail/ response from the <bf/Linux-PAM/ library. -The order of execution of these modules is that of the entries in the -<tt>/etc/pam.conf</tt> file; earlier entries are executed before later -ones. As of Linux-PAM v0.60, this <em/control-flag/ can be defined -with one of two syntaxes. - -<p> -The simpler (and historical) syntax for the control-flag is a single -keyword defined to indicate the severity of concern associated with -the success or failure of a specific module. There are four such -keywords: <tt/required/, <tt/requisite/, <tt/sufficient/ and -<tt/optional/. - -<p> -The Linux-PAM library interprets these keywords in the following -manner: - -<itemize> - -<item> <tt/required/; this indicates that the success of the module is -required for the <tt/module-type/ facility to succeed. Failure of this -module will not be apparent to the user until all of the remaining -modules (of the same <tt/module-type/) have been executed. - -<item> <tt/requisite/; like <tt/required/, however, in the case that -such a module returns a failure, control is directly returned to the -application. The return value is that associated with the <em/first/ -<tt/required/ or <tt/requisite/ module to fail. Note, this flag can be -used to protect against the possibility of a user getting the -opportunity to enter a password over an unsafe medium. It is -conceivable that such behavior might inform an attacker of valid -accounts on a system. This possibility should be weighed against the -not insignificant concerns of exposing a sensitive password in a -hostile environment. - -<item> <tt/sufficient/; the success of this module is deemed -`<em/sufficient/' to satisfy the <bf/Linux-PAM/ library that this -module-type has succeeded in its purpose. In the event that no -previous <tt/required/ module has failed, no more `<em/stacked/' -modules of this type are invoked. (Note, in this case subsequent -<tt/required/ modules are <bf/not/ invoked.). A failure of this module -is not deemed as fatal to satisfying the application that this -<tt/module-type/ has succeeded. - -<item> <tt/optional/; as its name suggests, this <tt/control-flag/ -marks the module as not being critical to the success or failure of -the user's application for service. In general, <bf/Linux-PAM/ -ignores such a module when determining if the module stack will -succeed or fail. However, in the absence of any definite successes or -failures of previous or subsequent stacked modules this module will -determine the nature of the response to the application. One example -of this latter case, is when the other modules return something like -<tt/PAM_IGNORE/. - -</itemize> - -<p> -The more elaborate (newer) syntax is much more specific and gives the -administrator a great deal of control over how the user is -authenticated. This form of the control flag is delimeted with square -brackets and consists of a series of <tt/value=action/ tokens: -<tscreen> -<verb> - [value1=action1 value2=action2 ...] -</verb> -</tscreen> - -<p> -Here, <tt/valueI/ is one of the following <em/return values/: -<tt/success/; <tt/open_err/; <tt/symbol_err/; <tt/service_err/; -<tt/system_err/; <tt/buf_err/; <tt/perm_denied/; <tt/auth_err/; -<tt/cred_insufficient/; <tt/authinfo_unavail/; <tt/user_unknown/; -<tt/maxtries/; <tt/new_authtok_reqd/; <tt/acct_expired/; -<tt/session_err/; <tt/cred_unavail/; <tt/cred_expired/; <tt/cred_err/; -<tt/no_module_data/; <tt/conv_err/; <tt/authtok_err/; -<tt/authtok_recover_err/; <tt/authtok_lock_busy/; -<tt/authtok_disable_aging/; <tt/try_again/; <tt/ignore/; <tt/abort/; -<tt/authtok_expired/; <tt/module_unknown/; <tt/bad_item/; and -<tt/default/. The last of these (<tt/default/) can be used to set the -action for those return values that are not explicitly defined. - -<p> -The <tt/actionI/ can be a positive integer or one of the following -tokens: <tt/ignore/; <tt/ok/; <tt/done/; <tt/bad/; <tt/die/; and -<tt/reset/. A positive integer, <tt/J/, when specified as the action, -can be used to indicate that the next <em/J/ modules of the current -module-type will be skipped. In this way, the administrator can -develop a moderately sophisticated stack of modules with a number of -different paths of execution. Which path is taken can be determined -by the reactions of individual modules. - -<p> -<itemize> -<item><tt/ignore/ - when used with a stack of modules, the module's - return status will not contribute to the return code the application - obtains. -<item><tt/bad/ - this action indicates that the return code should be - thought of as indicative of the module failing. If this module is - the first in the stack to fail, its status value will be used for - that of the whole stack. -<item><tt/die/ - equivalent to <tt/bad/ with the side effect of - terminating the module stack and PAM immediately returning to the - application. -<item><tt/ok/ - this tells <bf/PAM/ that the administrator thinks this - return code should contribute directly to the return code of the full - stack of modules. In other words, if the former state of the stack - would lead to a return of <tt/PAM_SUCCESS/, the module's return code - will override this value. Note, if the former state of the stack - holds some value that is indicative of a modules failure, this 'ok' - value will not be used to override that value. -<item><tt/done/ - equivalent to <tt/ok/ with the side effect of - terminating the module stack and PAM immediately returning to the - application. -<item><tt/reset/ - clear all memory of the state of the module stack and - start again with the next stacked module. -</itemize> - -<p> -Each of the four keywords: <tt/required/; <tt/requisite/; -<tt/sufficient/; and <tt/optional/, have an equivalent expression in -terms of the <tt/[...]/ syntax. They are as follows: -<itemize> -<item><tt/required/ is equivalent to -<tt/[success=ok new_authtok_reqd=ok ignore=ignore default=bad]/ -<item><tt/requisite/ is equivalent to -<tt/[success=ok new_authtok_reqd=ok ignore=ignore default=die]/ -<item><tt/sufficient/ is equivalent to -<tt/[success=done new_authtok_reqd=done default=ignore]/ -<item><tt/optional/ is equivalent to -<tt/[success=ok new_authtok_reqd=ok default=ignore]/ -</itemize> - -<p> -Just to get a feel for the power of this new syntax, here is a taste -of what you can do with it. With <bf/Linux-PAM-0.63/, the notion of -client plug-in agents was introduced. This is something that makes it -possible for PAM to support machine-machine authentication using the -transport protocol inherent to the client/server application. With -the ``<tt/[ ... value=action ... ]/'' control syntax, it is possible -for an application to be configured to support binary prompts with -compliant clients, but to gracefully fall over into an alternative -authentication mode for older, legacy, applications. - -<tag> <tt/module-path/</tag> - -The path-name of the dynamically loadable object file; <em/the -pluggable module/ itself. If the first character of the module path is -`<tt>/</tt>', it is assumed to be a complete path. If this is not the -case, the given module path is appended to the default module path: -<tt>/lib/security</tt> (but see the notes <ref id="text-conventions" -name="above">). - -<tag> <tt/args/</tag> - -The <tt/args/ are a list of tokens that are passed to the module when -it is invoked. Much like arguments to a typical Linux shell command. -Generally, valid arguments are optional and are specific to any given -module. Invalid arguments are ignored by a module, however, when -encountering an invalid argument, the module is required to write an -error to <tt/syslog(3)/. For a list of <em/generic/ options see the -next section. - -Note, if you wish to include spaces in an argument, you should -surround that argument with square brackets. For example: -<tscreen> -<verb> -squid auth required pam_mysql.so user=passwd_query passwd=mada \ - db=eminence [query=select user_name from internet_service where \ - user_name='%u' and password=PASSWORD('%p') and \ - service='web_proxy'] -</verb> -</tscreen> -Note, when using this convention, you can include `<tt/[/' characters -inside the string, and if you wish to include a `<tt/]/' character -inside the string that will survive the argument parsing, you should -use `<tt/\[/'. In other words: -<tscreen> -<verb> -[..[..\]..] --> ..[..].. -</verb> -</tscreen> - -</descrip> - -<p> -Any line in (one of) the configuration file(s), that is not formatted -correctly, will generally tend (erring on the side of caution) to make -the authentication process fail. A corresponding error is written to -the system log files with a call to <tt/syslog(3)/. - -<sect1>Directory based configuration - -<p> -More flexible than the single configuration file, as of version 0.56, -it is possible to configure <tt>libpam</tt> via the contents of the -<tt>/etc/pam.d/</tt> directory. In this case the directory is filled -with files each of which has a filename equal to a service-name (in -lower-case): it is the personal configuration file for the named -service. - -<p> -<bf/Linux-PAM/ can be compiled in one of two modes. The preferred -mode uses either <tt>/etc/pam.d/</tt> or <tt>/etc/pam.conf</tt> -configuration but not both. That is to say, if there is a -<tt>/etc/pam.d/</tt> directory then libpam only uses the files -contained in this directory. However, in the absence of the -<tt>/etc/pam.d/</tt> directory the <tt>/etc/pam.conf</tt> file is used -(this is likely to be the mode your preferred distribution uses). The -other mode is to use both <tt>/etc/pam.d/</tt> and -<tt>/etc/pam.conf</tt> in sequence. In this mode, entries in -<tt>/etc/pam.d/</tt> override those of <tt>/etc/pam.conf</tt>. - -The syntax of each file in <tt>/etc/pam.d/</tt> is similar to that of -the <tt>/etc/pam.conf</tt> file and is made up of lines of the -following form: -<tscreen> -<verb> -module-type control-flag module-path arguments -</verb> -</tscreen> -The only difference being that the <tt>service-name</tt> is not -present. The service-name is of course the name of the given -configuration file. For example, <tt>/etc/pam.d/login</tt> contains -the configuration for the <em>login</em> service. - -<p> -This method of configuration has a number of advantages over the -single file approach. We list them here to assist the reader in -deciding which scheme to adopt: - -<p> -<itemize> - -<item>A lower chance of misconfiguring an application. There is one -less field to mis-type when editing the configuration files by hand. - -<item>Easier to maintain. One application may be reconfigured without -risk of interfering with other applications on the system. - -<item>It is possible to symbolically link different services -configuration files to a single file. This makes it easier to keep the -system policy for access consistent across different applications. -(It should be noted, to conserve space, it is equally possible to -<em>hard</em> link a number of configuration files. However, care -should be taken when administering this arrangement as editing a hard -linked file is likely to break the link.) - -<item>A potential for quicker configuration file parsing. Only the -relevant entries are parsed when a service gets bound to its modules. - -<item>It is possible to limit read access to individual <bf/Linux-PAM/ -configuration files using the file protections of the filesystem. - -<item>Package management becomes simpler. Every time a new -application is installed, it can be accompanied by an -<tt>/etc/pam.d/</tt><em>xxxxxx</em> file. - -</itemize> - -<sect1>Generic optional arguments - -<p> -The following are optional arguments which are likely to be understood -by any module. Arguments (including these) are in general -<em/optional/. - -<p> -<descrip> -<tag><tt/debug/</tag> - -Use the <tt/syslog(3)/ call to log debugging information to the system -log files. - -<tag> <tt/no_warn/</tag> - -Instruct module to not give warning messages to the application. - -<tag> <tt/use_first_pass/</tag> - -The module should not prompt the user for a password. Instead, it -should obtain the previously typed password (from the preceding -<tt/auth/ module), and use that. If that doesn't work, then the user -will not be authenticated. (This option is intended for <tt/auth/ -and <tt/password/ modules only). - -<tag> <tt/try_first_pass/</tag> - -The module should attempt authentication with the previously typed -password (from the preceding <tt/auth/ module). If that doesn't work, -then the user is prompted for a password. (This option is intended for -<tt/auth/ modules only). - -<tag> <tt/use_mapped_pass/</tag> - -This argument is not currently supported by any of the modules in the -<bf/Linux-PAM/ distribution because of possible consequences -associated with U.S. encryption exporting restrictions. Within the -U.S., module developers are, of course, free to implement it (as are -developers in other countries). For compatibility reasons we describe -its use as suggested in the <bf/DCE-RFC 86.0/, see section <ref -id="see-also-sec" name="bibliography"> for a pointer to this document. - -<p> -The <tt/use_mapped_pass/ argument instructs the module to take the -clear text authentication token entered by a previous module (that -requests such a token) and use it to generate an encryption/decryption -key with which to safely store/retrieve the authentication token -required for this module. In this way the user can enter a single -authentication token and be quietly authenticated by a number of -stacked modules. Obviously a convenient feature that necessarily -requires some reliably strong encryption to make it secure. -This argument is intended for the <tt/auth/ and <tt/password/ module -types only. - -<tag><tt/expose_account/</tag> - -<p> -In general the leakage of some information about user accounts is not -a secure policy for modules to adopt. Sometimes information such as -users names or home directories, or preferred shell, can be used to -attack a user's account. In some circumstances, however, this sort of -information is not deemed a threat: displaying a user's full name when -asking them for a password in a secured environment could also be -called being 'friendly'. The <tt/expose_account/ argument is a -standard module argument to encourage a module to be less discrete -about account information as it is deemed appropriate by the local -administrator. - -</descrip> - -<sect1>Example configuration file entries - -<p> -In this section, we give some examples of entries that can be present -in the <bf/Linux-PAM/ configuration file. As a first attempt at -configuring your system you could do worse than to implement these. - -<sect2>Default policy - -<p> -If a system is to be considered secure, it had better have a -reasonably secure `<tt/OTHER/' entry. The following is a paranoid -setting (which is not a bad place to start!): -<tscreen> -<verb> -# -# default; deny access -# -OTHER auth required pam_deny.so -OTHER account required pam_deny.so -OTHER password required pam_deny.so -OTHER session required pam_deny.so -</verb> -</tscreen> -Whilst fundamentally a secure default, this is not very sympathetic to -a misconfigured system. For example, such a system is vulnerable to -locking everyone out should the rest of the file become badly written. - -<p> -The module <tt/pam_deny/ (documented in a later section) is not very -sophisticated. For example, it logs no information when it is invoked -so unless the users of a system contact the administrator when failing -to execute a service application, the administrator may go for a long -while in ignorance of the fact that his system is misconfigured. - -<p> -The addition of the following line before those in the above example -would provide a suitable warning to the administrator. -<tscreen> -<verb> -# -# default; wake up! This application is not configured -# -OTHER auth required pam_warn.so -OTHER password required pam_warn.so -</verb> -</tscreen> -Having two ``<tt/OTHER auth/'' lines is an example of stacking. - -<p> -On a system that uses the <tt>/etc/pam.d/</tt> configuration, the -corresponding default setup would be achieved with the following file: -<tscreen> -<verb> -# -# default configuration: /etc/pam.d/other -# -auth required pam_warn.so -auth required pam_deny.so -account required pam_deny.so -password required pam_warn.so -password required pam_deny.so -session required pam_deny.so -</verb> -</tscreen> -This is the only explicit example we give for an <tt>/etc/pam.d/</tt> -file. In general, it should be clear how to transpose the remaining -examples to this configuration scheme. - -<p> -On a less sensitive computer, one on which the system administrator -wishes to remain ignorant of much of the power of <tt/Linux-PAM/, the -following selection of lines (in <tt>/etc/pam.conf</tt>) is likely to -mimic the historically familiar Linux setup. -<tscreen> -<verb> -# -# default; standard UN*X access -# -OTHER auth required pam_unix.so -OTHER account required pam_unix.so -OTHER password required pam_unix.so -OTHER session required pam_unix.so -</verb> -</tscreen> -In general this will provide a starting place for most applications. -Unfortunately, most is not all. One application that might require -additional lines is <em/ftpd/ if you wish to enable -<em/anonymous-ftp/. - -<p> -To enable anonymous-ftp, the following lines might be used to replace -the default (<tt/OTHER/) ones. (<bf/*WARNING*/ as of 1996/12/28 this -does not work correctly with any ftpd. Consequently, this description -may be subject to change or the application will be fixed.) -<tscreen> -<verb> -# -# ftpd; add ftp-specifics. These lines enable anonymous ftp over -# standard UN*X access (the listfile entry blocks access to -# users listed in /etc/ftpusers) -# -ftpd auth sufficient pam_ftp.so -ftpd auth required pam_unix_auth.so use_first_pass -ftpd auth required pam_listfile.so \ - onerr=succeed item=user sense=deny file=/etc/ftpusers -</verb> -</tscreen> -Note, the second line is necessary since the default entries are -ignored by a service application (here <em/ftpd/) if there are -<em/any/ entries in <tt>/etc/pam.conf</tt> for that specified service. -Again, this is an example of authentication module stacking. Note the -use of the <tt/sufficient/ control-flag. It says that ``if this module -authenticates the user, ignore the subsequent <tt/auth/ -modules''. Also note the use of the ``<tt/use_first_pass/'' -module-argument, this instructs the UN*X authentication module that it -is not to prompt for a password but rely on one already having been -obtained by the <tt/pam_ftp/ module. - -<sect>Security issues of Linux-PAM - -<p> -This section will discuss good practices for using PAM in a secure -manner. <em>It is currently sadly lacking...suggestions are -welcome!</em> - -<sect1>If something goes wrong - -<p> -<bf/Linux-PAM/ has the potential to seriously change the security of -your system. You can choose to have no security or absolute security -(no access permitted). In general, <bf/Linux-PAM/ errs towards the -latter. Any number of configuration errors can dissable access to -your system partially, or completely. - -<p> -The most dramatic problem that is likely to be encountered when -configuring <bf/Linux-PAM/ is that of <em>deleting</em> the -configuration file(s): <tt>/etc/pam.d/*</tt> and/or -<tt>/etc/pam.conf</tt>. This will lock you out of your own system! - -<p> -To recover, your best bet is to reboot the system in single user mode -and set about correcting things from there. The following has been -<em>adapted</em> from a life-saving email on the subject from David -Wood: -<verb> -> What the hell do I do now? - -OK, don't panic. The first thing you have to realize is that -this happens to 50% of users who ever do anything with PAM. -It happened here, not once, not twice, but three times, all -different, and in the end, the solution was the same every -time. - -First, I hope you installed LILO with a delay. If you can, -reboot, hit shift or tab or something and type: - - LILO boot: linux single - -(Replace 'linux' with 'name-of-your-normal-linux-image'). -This will let you in without logging in. Ever wondered how -easy it is to break into a linux machine from the console? -Now you know. - -If you can't do that, then get yourself a bootkernel floppy -and a root disk a-la slackware's rescue.gz. (Red Hat's -installation disks can be used in this mode too.) - -In either case, the point is to get back your root prompt. - -Second, I'm going to assume that you haven't completely -nuked your pam installation - just your configuration files. -Here's how you make your configs nice again: - - cd /etc - mv pam.conf pam.conf.orig - mv pam.d pam.d.orig - mkdir pam.d - cd pam.d - -and then use vi to create a file called "other" in this -directory. It should contain the following four lines: - - auth required pam_unix.so - account required pam_unix.so - password required pam_unix.so - session required pam_unix.so - -Now you have the simplest possible PAM configuration that -will work the way you're used to. Everything should -magically start to work again. Try it out by hitting ALT-F2 -and logging in on another virtual console. If it doesn't -work, you have bigger problems, or you've mistyped -something. One of the wonders of this system (seriously, -perhaps) is that if you mistype anything in the conf files, -you usually get no error reporting of any kind on the -console - just some entries in the log file. So look there! -(Try 'tail /var/log/messages'.) - -From here you can go back and get a real configuration -going, hopefully after you've tested it first on a machine -you don't care about screwing up. :/ - -Some pointers (to make everything "right" with Red Hat...): - - Install the newest pam, pamconfig, and pwdb from the - redhat current directory, and do it all on the same - command line with rpm... - - rpm -Uvh [maybe --force too] pam-* pamconfig-* pwdb-* - - Then make sure you install (or reinstall) the newest - version of libc, util-linux, wuftp, and NetKit. For - kicks you might try installing the newest versions of - the affected x apps, like xlock, but I haven't gotten - those to work at all yet. - -</verb> - -<sect1>Avoid having a weak `other' configuration - -<p> -It is not a good thing to have a weak default (<tt/OTHER/) entry. -This service is the default configuration for all PAM aware -applications and if it is weak, your system is likely to be vulnerable -to attack. - -<p> -Here is a sample "other" configuration file. The <em/pam_deny/ module will -deny access and the <em/pam_warn/ module will send a syslog message to -<tt/auth.notice/: - -<p> -<tscreen> -<verb> -# -# The PAM configuration file for the `other' service -# -auth required pam_deny.so -auth required pam_warn.so -account required pam_deny.so -account required pam_warn.so -password required pam_deny.so -password required pam_warn.so -session required pam_deny.so -session required pam_warn.so -</verb> -</tscreen> - -<sect>A reference guide for available modules - -<p> -Here, we collect together some descriptions of the various modules -available for <bf/Linux-PAM/. In general these modules should be -freely available. Where this is not the case, it will be indicated. - -<p> -Also please note the comments contained in the section <ref -id="text-conventions" name="on text conventions above"> when copying -the examples listed below. - -<!-- insert-file MODULES-SGML --> - -<sect>Files - -<p><descrip> - -<tag><tt>/lib/libpam.so.*</tt></tag> - -the shared library providing applications with access to -<bf/Linux-PAM/. - -<tag><tt>/etc/pam.conf</tt></tag> - -the <bf/Linux-PAM/ configuration file. - -<tag><tt>/lib/security/pam_*.so</tt></tag> - -the primary location for <bf/Linux-PAM/ dynamically loadable object -files; the modules. - -</descrip> - -<sect>See also<label id="see-also-sec"> - -<p><itemize> - -<item>The <bf/Linux-PAM/ Application Writers' Guide. - -<item>The <bf/Linux-PAM/ Module Writers' Guide. - -<item>The V. Samar and R. Schemers (SunSoft), ``UNIFIED LOGIN WITH -PLUGGABLE AUTHENTICATION MODULES'', Open Software Foundation Request -For Comments 86.0, October 1995. See this url: -<tt><htmlurl -url="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz" -name="http://www.kernel.org/pub/linux/libs/pam/pre/doc/rfc86.0.txt.gz"></tt> - -</itemize> - -<sect>Notes - -<p> -I intend to put development comments here... like ``at the moment -this isn't actually supported''. At release time what ever is in -this section will be placed in the Bugs section below! :) - -<p> -Are we going to be able to support the <tt/use_mapped_pass/ module -argument? Anyone know a cheap (free) good lawyer?! - -<p> -<itemize> -<item> -This issue may go away, as Sun have investigated adding a new -management group for mappings. In this way, libpam would have mapping -modules that could securely store passwords using strong cryptography -and in such a way that they need not be distributed with Linux-PAM. -</itemize> - -<sect>Author/acknowledgments - -<p> -This document was written by Andrew G. Morgan (morgan@kernel.org) -with many contributions from -<!-- insert-file CREDITS --> - -<p> -Thanks are also due to Sun Microsystems, especially to Vipin Samar and -Charlie Lai for their advice. At an early stage in the development of -<bf/Linux-PAM/, Sun graciously made the documentation for their -implementation of PAM available. This act greatly accelerated the -development of <bf/Linux-PAM/. - -<sect>Bugs/omissions - -<p> -More PAM modules are being developed all the time. It is unlikely that -this document will ever be truely up to date! - -<p> -This manual is unfinished. Only a partial list of people is credited -for all the good work they have done. - -<sect>Copyright information for this document - -<p> -Copyright (c) Andrew G. Morgan 1996-2002. All rights reserved. -<newline> -Email: <tt><morgan@kernel.org></tt> - -<p> -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -<p> -<itemize> - -<item> -1. Redistributions of source code must retain the above copyright - notice, and the entire permission notice in its entirety, - including the disclaimer of warranties. - -<item> -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -<item> -3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -</itemize> - -<p> -<bf/Alternatively/, this product may be distributed under the terms of -the GNU General Public License (GPL), in which case the provisions of -the GNU GPL are required <bf/instead of/ the above restrictions. -(This clause is necessary due to a potential bad interaction between -the GNU GPL and the restrictions contained in a BSD-style copyright.) - -<p> -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -<p> -<tt>$Id$</tt> - -</article> diff --git a/doc/pdf/.cvsignore b/doc/pdf/.cvsignore deleted file mode 100644 index a1363379..00000000 --- a/doc/pdf/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -*.pdf diff --git a/doc/pdf/README b/doc/pdf/README deleted file mode 100644 index 82efcd46..00000000 --- a/doc/pdf/README +++ /dev/null @@ -1,3 +0,0 @@ -$Id$ - -a directory for PDF versions of the documentation diff --git a/doc/ps/.cvsignore b/doc/ps/.cvsignore deleted file mode 100644 index fa1d1137..00000000 --- a/doc/ps/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -pam*.ps diff --git a/doc/ps/README b/doc/ps/README deleted file mode 100644 index 32a833f6..00000000 --- a/doc/ps/README +++ /dev/null @@ -1,3 +0,0 @@ -$Id$ - -this is the directory for the PostScript documentation diff --git a/doc/specs/.cvsignore b/doc/specs/.cvsignore deleted file mode 100644 index d564ba7e..00000000 --- a/doc/specs/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -draft-morgan-pam-*.txt diff --git a/doc/specs/draft-morgan-pam.raw b/doc/specs/draft-morgan-pam.raw deleted file mode 100644 index 45109f45..00000000 --- a/doc/specs/draft-morgan-pam.raw +++ /dev/null @@ -1,764 +0,0 @@ -Open-PAM working group ## A.G. Morgan -Internet Draft: ## Dec 8, 2001 -Document: draft-morgan-pam-08.txt ## -Expires: June 8, 2002 ## -Obsoletes: draft-morgan-pam-07.txt## - -## Pluggable Authentication Modules (PAM) ## - -#$ Status of this memo - -This document is a draft specification. Its contents are subject to -change with revision. The latest version of this draft may be obtained -from here: - - http://www.kernel.org/pub/linux/libs/pam/pre/doc/ - -As - - Linux-PAM-'version'-docs.tar.gz - -It is also contained in the Linux-PAM tar ball. - -#$ Abstract - -This document is concerned with the definition of a general -infrastructure for module based authentication. The infrastructure is -named Pluggable Authentication Modules (PAM for short). - -#$ Introduction - -Computers are tools. They provide services to people and other -computers (collectively we shall call these _users_ entities). In -order to provide convenient, reliable and individual service to -different entities, it is common for entities to be labelled. Having -defined a label as referring to a some specific entity, the label is -used for the purpose of protecting and allocating data resources. - -All modern operating systems have a notion of labelled entities and -all modern operating systems face a common problem: how to -authenticate the association of a predefined label with applicant -entities. - -There are as many authentication methods as one might care to count. -None of them are perfect and none of them are invulnerable. In -general, any given authentication method becomes weaker over time. It -is common then for new authentication methods to be developed in -response to newly discovered weaknesses in the old authentication -methods. - -The problem with inventing new authentication methods is the fact that -old applications do not support them. This contributes to an inertia -that discourages the overhaul of weakly protected systems. Another -problem is that individuals (people) are frequently powerless to layer -the protective authentication around their systems. They are forced -to rely on single (lowest common denominator) authentication schemes -even in situations where this is far from appropriate. - -PAM, as discussed in this document, is a generalization of the -approach first introduced in [#$R#{OSF_RFC_PAM}]. In short, it is a -general framework of interfaces that abstract the process of -authentication. With PAM, a service provider can custom protect -individual services to the level that they deem is appropriate. - -PAM has nothing explicit to say about transport layer encryption. -Within the context of this document encryption and/or compression of -data exchanges are application specific (strictly between client and -server) and orthogonal to the process of authentication. - -#$ Definitions - -Here we pose the authentication problem as one of configuring defined -interfaces between two entities. - -#$$#{players} Players in the authentication process - -PAM reserves the following words to specify unique entities in the -authentication process: - - applicant - the entity (user) initiating an application for service - [PAM associates the PAM_RUSER _item_ with this requesting user]. - - arbitrator - the entity (user) under whose identity the service application - is negotiated and with whose authority service is granted. - - user - the entity (user) whose identity is being authenticated - [PAM associates the PAM_USER _item_ with this identity]. - - server - the application that provides service, or acts as an - authenticated gateway to the requested service. This - application is completely responsible for the server end of - the transport layer connecting the server to the client. - PAM makes no assumptions about how data is encapsulated for - exchanges between the server and the client, only that full - octet sequences can be freely exchanged without corruption. - - client - application providing the direct/primary interface to - applicant. This application is completely responsible - for the client end of the transport layer connecting the - server to the client. PAM makes no assumptions about how data - is encapsulated for exchanges between the server and the - client, only that full octet sequences can be freely - exchanged without corruption. - - module - authentication binary that provides server-side support for - some (arbitrary) authentication method. - - agent - authentication binary that provides client-side support for - some (arbitrary) authentication method. - -Here is a diagram to help orient the reader: - -## +-------+ +--------+ ## -## . . . . .| agent | .| module | ## -## . +-------+ .+--------+ ## -## V | . | ## -## . | V | ## -## +---------+ +-------+ . +------+ ## -## | | |libpamc| . |libpam| ## -## | | +-------+ . +------+ ## -## |applicant| | . | ## -## | | +--------+ +----------+ ## -## | |---| client |-----------| server | ## -## +---------+ +--------+ +----------+ ## - -Solid lines connecting the boxes represent two-way interaction. The -dotted-directed lines indicate an optional connection beteween the -plugin module (agent) and the server (applicant). In the case of the -module, this represents the module invoking the 'conversation' -callback function provided to libpam by the server application when it -inititializes the libpam library. In the case of the agent, this may -be some out-of-PAM API interaction (for example directly displaying a -dialog box under X). - -#$$ Defined Data Types - -In this draft, we define two composite data types, the text string and -the binary prompt. They are the data types used to communicate -authentication requests and responses. - -#$$$#{text_string} text string - -The text string is a simple sequence of non-NUL (NUL = 0x00) -octets. Terminated with a single NUL (0x00) octet. The character set -employed in the octet sequence may be negotiated out of band, but -defaults to utf-8. - -## --------------------------- ## -## [ character data | NUL ] ## -## [ octet sequence | 0x00 ] ## -## --------------------------- ## - -Within the rest of this text, PAM text strings are delimited with a -pair of double quotes. Example, "this" = {'t';'h';'i';'s';0x00}. - -#$$$#{binary_prompt} binary prompt - -A binary prompt consists of a stream of octets arranged as follows: - -## ---------------------------------------- ## -## [ u32 | u8 | (length-5 octets) ] ## -## [ length | control | data ] ## -## ---------------------------------------- ## - -That is, a 32-bit unsigned integer in network byte order, a single -unsigned byte of control information and a sequence of octets of -length (length-5). The composition of the _data_ is context dependent -but is generally not a concern for either the server or the client. It -is very much the concern of modules and agents. - -For purposes of interoperability, we define the following control -characters as legal. - -## value symbol description ## -## ------------------------------------------------- ## -## 0x01 PAM_BPC_OK - continuation packet ## -## 0x02 PAM_BPC_SELECT - initialization packet ## -## 0x03 PAM_BPC_DONE - termination packet ## -## 0x04 PAM_BPC_FAIL - unable to execute ## - -The following control characters are only legal for exchanges between -an agent and a client (it is the responsibility of the client to -enforce this rule in the face of a rogue server): - -## 0x41 PAM_BPC_GETENV - obtain client env.var ## -## 0x42 PAM_BPC_PUTENV - set client env.var ## -## 0x43 PAM_BPC_TEXT - display message ## -## 0x44 PAM_BPC_ERROR - display error message ## -## 0x45 PAM_BPC_PROMPT - echo'd text prompt ## -## 0x46 PAM_BPC_PASS - non-echo'd text prompt ## -## 0x46 PAM_BPC_STATUS - ping all active clients## -## 0x47 PAM_BPC_ABORT - please abort session ## - -Note, length is always equal to the total length of the binary -prompt and represented by a network ordered unsigned 32 bit integer. - -#$$$$#{agent_ids} PAM_BPC_SELECT binary prompts - -Binary prompts of control type PAM_BPC_SELECT have a defined -data part. It is composed of three elements: - - {agent_id;'/';data} - -The agent_id is a sequence of characters satisfying the following -regexp: - - /^[a-z0-9\_]+(@[a-z0-9\_.]+)?$/ - -and has a specific form for each independent agent. - -o Agent_ids that do not contain an at-sign (@) are to be considered as - representing some authentication mode that is a "public - standard" see reference [#$R#{PAM_STD_AGENTIDS}]. Registered names - MUST NOT contain an at-sign (@). - -o Anyone can define additional agents by using names in the format - name@domainname, e.g. "ouragent@example.com". The part following - the at-sign MUST be a valid fully qualified internet domain name - [RFC-1034] controlled by the person or organization defining the - name. (Said another way, if you control the email address that - your agent has as an identifier, they you are entitled to use - this identifier.) It is up to each domain how it manages its local - namespace. - -The '/' character is a mandatory delimiter, indicating the end of the -agent_id. The trailing data is of a format specific to the agent with -the given agent_id. - - -#$$ Special cases - -In a previous section (#{players}) we identified the most general -selection of authentication participants. In the case of network -authentication, it is straightforward to ascribe identities to the -defined participants. However, there are also special (less general) -cases that we recognize here. - -The primary authentication step, when a user is directly introduced -into a computer system (log's on to a workstation) is a special case. -In this situation, the client and the server are generally one -application. Before authenticating such a user, the applicant is -formally unknown: PAM_RUSER is NULL. - -Some client-server implementations (telnet for example) provide -effective full tty connections. In these cases, the four simple text -string prompting cases (see below) can be handled as in the primary -login step. In other words, the server absorbs most of the overhead of -propagating authentication messages. In these cases, there needs to be -special client/server support for handling binary prompts. - -In some circumstances, a legacy network transfer protocol can carry -authentication information. In such cases, a desire to support legacy -clients (with no client-side support for PAM) will neccessitate the -'hardcoding' of an agent protocol into the server application. Whilst -against the spirit of PAM, this special casing can be managed by the -server's 'conversation function' (see below). The guiding principle -when implementing such support is for the application developer to -relegate the authentication process to the PAM module -- simply -performing a transcription of data from binary-prompt to legacy -network 'packet' and visa-versa for propagating replies back to the -driving PAM module. A common case of this is with network protocols -that define an initialization packet of "user+password". In such cases -one should attempt to support the "userpass" agent-id and its defined -protocol. - -#$ Defined interfaces for information flow - -Here, we discuss the information exchange interfaces between the -players in the authentication process. It should be understood that -the server side is responsible for driving the authentication of the -applicant. Notably, every request received by the client from the -server must be matched with a single response from the client to the -server. - -#$$#{applicant_client} Applicant <-> client - -Once the client is invoked, requests to the applicant entity are -initiated by the client application. General clients are able to make -the following requests directly to an applicant: - - echo text string - echo error text string - prompt with text string for echo'd text string input - prompt with text string for concealed text string input - -the nature of the interface provided by the client for the benefit of -the applicant entity is client specific and not defined by PAM. - -#$$#{client_agent} Client <-> agent - -In general, authentication schemes require more modes of exchange than -the four defined in the previous section (#{applicant_client}). This -provides a role for client-loadable agents. The client and agent -exchange binary-messages that can have one of the following forms: - - client -> agent - binary prompt agent expecting binary prompt reply to client - - agent -> client - binary prompt reply from agent to clients binary prompt - -Following the acceptance of a binary prompt by the agent, the agent -may attempt to exchange information with the client before returning -its binary prompt reply. Permitted exchanges are binary prompts of the -following types: - - agent -> client - set environment variable (A) - get environment variable (B) - echo text string (C) - echo error text string (D) - prompt for echo'd text string input (E) - prompt for concealed text string input (F) - -In response to these prompts, the client must legitimately respond -with a corresponding binary prompt reply. We list a complete set of -example exchanges, including each type of legitimate response (passes -and a single fail): - -## Type | Agent request | Client response ## -## --------------------------------------------------------------- ## -## (A) | {13;PAM_BPC_PUTENV;"FOO=BAR"} | {5;PAM_BPC_OK;} ## -## | {10;PAM_BPC_PUTENV;"FOO="} | {5;PAM_BPC_OK;} ## -## | {9;PAM_BPC_PUTENV;"FOO"} (*) | {5;PAM_BPC_OK;} ## -## | {9;PAM_BPC_PUTENV;"BAR"} (*) | {5;PAM_BPC_FAIL;} ## -## --------------------------------------------------------------- ## -## (B) | {10;PAM_BPC_GETENV;"TERM"} | {11;PAM_BPC_OK;"vt100"} ## -## | {9;PAM_BPC_GETENV;"FOO"} | {5;PAM_BPC_FAIL;} ## -## --------------------------------------------------------------- ## -## (C) | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_OK;} ## -## | {12;PAM_BPC_TEXT;"hello!"} | {5;PAM_BPC_FAIL;} ## -## --------------------------------------------------------------- ## -## (D) | {11;PAM_BPC_ERROR;"ouch!"} | {5;PAM_BPC_OK;} ## -## | {11;PAM_BPC_ERROR;"ouch!"} | {5;PAM_BPC_FAIL;} ## -## --------------------------------------------------------------- ## -## (E) | {13;PAM_BPC_PROMPT;"login: "} | {9;PAM_BPC_OK;"joe"} ## -## | {13;PAM_BPC_PROMPT;"login: "} | {6;PAM_BPC_OK;""} ## -## | {13;PAM_BPC_PROMPT;"login: "} | {5;PAM_BPC_FAIL;} ## -## --------------------------------------------------------------- ## -## (F) | {16;PAM_BPC_PASS;"password: "} | {9;PAM_BPC_OK;"XYZ"} ## -## | {16;PAM_BPC_PASS;"password: "} | {6;PAM_BPC_OK;""} ## -## | {16;PAM_BPC_PASS;"password: "} | {5;PAM_BPC_FAIL;} ## - -(*) Used to attempt the removal of a pre-existing environment -variable. - -#$$ Client <-> server - -Once the client has established a connection with the server (the -nature of the transport protocol is not specified by PAM), the server -is responsible for driving the authentication process. - -General servers can request the following from the client: - - (to be forwarded by the client to the applicant) - echo text string - echo error text string - prompt for echo'd text string response - prompt for concealed text string response - - (to be forwarded by the client to the appropriate agent) - binary prompt for a binary prompt response - -Client side agents are required to process binary prompts. The -agents' binary prompt responses are returned to the server. - -#$$ Server <-> module - -Modules drive the authentication process. The server provides a -conversation function with which it encapsulates module-generated -requests and exchanges them with the client. Every message sent by a -module should be acknowledged. - -General conversation functions can support the following five -conversation requests: - - echo text string - echo error string - prompt for echo'd text string response - prompt for concealed text string response - binary prompt for binary prompt response - -The server is responsible for redirecting these requests to the -client. - -#$ C API for application interfaces (client and server) - -#$$ Applicant <-> client - -No API is defined for this interface. The interface is considered to -be specific to the client application. Example applications include -terminal login, (X)windows login, machine file transfer applications. - -All that is important is that the client application is able to -present the applicant with textual output and to receive textual -input from the applicant. The forms of textual exchange are listed -in an earlier section (#{applicant_client}). Other methods of -data input/output are better suited to being handled via an -authentication agent. - -#$$ Client <-> agent - -The client makes use of a general API for communicating with -agents. The client is not required to communicate directly with -available agents, instead a layer of abstraction (in the form of a -library: libpamc) takes care of loading and maintaining communication -with all requested agents. This layer of abstraction will choose which -agents to interact with based on the content of binary prompts it -receives that have the control type PAM_BPC_SELECT. - -#$$$ Client <-> libpamc - -#$$$$ Compilation information - -The C-header file provided for client-agent abstraction is included -with the following source line: - - \#include <security/pam_client.h> - -The library providing the corresponding client-agent abstraction -functions is, libpamc. - - cc .... -lpamc - -#$$$$ Initializing libpamc - -The libpamc library is initialized with a call to the following -function: - - pamc_handle_t pamc_start(void); - -This function is responsible for configuring the library and -registering the location of available agents. The location of the -available agents on the system is implementation specific. - -pamc_start() function returns NULL on failure. Otherwise, the return -value is a pointer to an opaque data type which provides a handle to -the libpamc library. On systems where threading is available, the -libpamc libraray is thread safe provided a single (pamc_handler_t *) -is used by each thread. - -#$$$$ Client (Applicant) selection of agents - -For the purpose of applicant and client review of available agents, -the following function is provided. - - char **pamc_list_agents(pamc_handle_t pch); - -This returns a list of pointers to the agent_id's of the agents which -are available on the system. The list is terminated by a NULL pointer. -It is the clients responsibility to free this memory area by calling -free() on each agent id and the block of agent_id pointers in the -result. - -PAM represents a server-driven authentication model, so by default -any available agent may be invoked in the authentication process. - -#$$$$$ Client demands agent - -If the client requires that a specific authentication agent is -satisfied during the authentication process, then the client should -call the following function, immediately after obtaining a -pamc_handle_t from pamc_start(). - - int pamc_load(pamc_handle_t pch, const char *agent_id); - -agent_id is a PAM text string (see section #{agent_ids}) and is not -suffixed with a '/' delimiter. The return value for this function is: - - PAM_BPC_TRUE - agent located and loaded. - PAM_BPC_FALSE - agent is not available. - -Note, although the agent is loaded, no data is fed to it. The agent's -opportunity to inform the client that it does not trust the server is -when the agent is shutdown. - -#$$$$$ Client marks agent as unusable - -The applicant might prefer that a named agent is marked as not -available. To do this, the client would invoke the following function -immediately after obtaining a pamc_handle_t from pam_start(). - - int pamc_disable(pamc_handle_t pch, const char *agent_id); - -here agent_id is a PAM text string containing an agent_id (section -#{agent_ids}). - -The return value for this function is: - - PAM_BPC_TRUE - agent is disabled. This is the response - independent of whether the agent is locally - available. - - PAM_BPC_FALSE - agent cannot be disabled (this may be because - it has already been invoked). - -#$$$$ Allocating and manipulating binary prompts - -All conversation between an client and an agent takes place with -respect to binary prompts. A binary prompt (see section #{binary_prompt}), is -obtained, resized and deleted via the following C-macro: - - CREATION of a binary prompt with control X1 and data length Y1: - - pamc_bp_t prompt = NULL; - PAM_BP_RENEW(&prompt, X1, Y1); - - REPLACEMENT of a binary prompt with a control X2 and data length Y2: - - PAM_BP_RENEW(&prompt, X2, Y2); - - DELETION of a binary prompt (the referenced prompt is scrubbed): - - PAM_BP_RENEW(&prompt, 0, 0); - -Note, the PAM_BP_RENEW macro always overwrites any prompt that you -call it with, deleting and liberating the old contents in a secure -fashion. Also note that PAM_BP_RENEW, when returning a prompt of data -size Y1>0, will always append a '\0' byte to the end of the prompt (at -data offset Y1). It is thus, by definition, acceptable to treat the -data contents of a binary packet as a text string (see #{text_string}). - - FILLING a binary prompt from a memory pointer U1 from offset O1 of - length L1: - - PAM_BP_FILL(prompt, O1, L1, U1); - - the CONTROL type for the packet can be obtained as follows: - - control = PAM_PB_CONTROL(prompt); - - the LENGTH of a data within the prompt (_excluding_ its header - information) can be obtained as follows: - - length = PAM_BP_LENGTH(prompt); - - the total SIZE of the prompt (_including_ its header information) - can be obtained as follows: - - size = PAM_BP_SIZE(prompt); - - EXTRACTING data from a binary prompt from offset O2 of length L2 to - a memory pointer U2: - - PAM_BP_EXTRACT(prompt, O2, L2, U2); - - If you require direct access to the raw prompt DATA, you should use - the following macro: - - __u8 *raw_data = PAM_BP_DATA(prompt); - -#$$$$ Client<->agent conversations - -All exchanges of binary prompts with agents are handled with the -single function: - - int pamc_converse(pamc_handle_t *pch, pamc_bp_t *prompt_p); - -The return value for pamc_converse(...) is PAM_BPC_TRUE when there is -a response packet and PAM_BPC_FALSE when the client is unable to -handle the request represented by the original prompt. In this latter -case, *prompt_p is set to NULL. - -This function takes a binary prompt and returns a replacement binary -prompt that is either a request from an agent to be acted upon by the -client or the 'result' which should be forwarded to the server. In the -former case, the following macro will return 1 (PAM_BPC_TRUE) and in -all other cases, 0 (PAM_BPC_FALSE): - - PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt) - -Note, all non-NULL binary prompts returned by pamc_converse(...), are -terminated with a '\0', even when the full length of the prompt (as -returned by the agent) does not contain this delimiter. This is a -defined property of the PAM_BP_RENEW macro, and can be relied upon. - -Important security note: in certain implementations, agents are -implemented by executable binaries, which are transparently loaded and -managed by the PAM client library. To ensure there is never a leakage -of elevated privilege to an unprivileged agent, the client application -should go to some effort to lower its level of privilege. It remains -the responsibility of the applicant and the client to ensure that it -is not compromised by a rogue agent. - -#$$$$ Status of agents - - int pamc_status(pamc_handle_t *pch, pamc_bp_t *prompt_p); - -At any time, the client may ping all active agents for their status -(with a PAM_BPC_STATUS binary prompt). If any agent replies with -PAM_BPC_ABORT, the client is responsible for terminating the -connection to the server and then terminating all agents with a call -to pamc_end(). In such cases, the return value of pamc_status() is -PAM_BPC_FALSE. - -If the return status of pamc_status() is PAM_BPC_TRUE and *prompt_p is -non-NULL, then an agent is requesting access to a server module. - -XXX - how this information gets propagated to the server, and - ultimately to the server's module is yet to be determined. - -#$$$$ Termination of agents - -When closing the authentication session and severing the connection -between a client and a selection of agents, the following function is -used: - - int pamc_end(pamc_handle_t *pch); - -Following a call to pamc_end, the pamc_handle_t will be invalid. - -The return value for this function is one of the following: - - PAM_BPC_TRUE - all invoked agents are content with - authentication (the server is _not_ judged - _un_trustworthy by any agent) - - PAM_BPC_FALSE - one or more agents were unsatisfied at - being terminated. In general, the client - should terminate its connection to the - server and indicate to the applicant that - the server is untrusted. - -#$$$ libpamc <-> agents - -The agents are manipulated from within libpamc. Each agent is an -executable in its own right. This permits the agent to have access to -sensitive data not accessible directly from the client. The mode of -communication between libpamc and an agent is through a pair of -pipes. The agent reads binary prompts (section #{binary_prompt}) -through its standard input file descriptor and writes response (to the -server) binary prompts and instruction binary prompts (instructions -for the client) through its standard output file descriptor. - -#$$ Client <-> server - -This interface is concerned with the exchange of text and binary -prompts between the client application and the server application. No -API is provided for this as it is considered specific to the transport -protocol shared by the client and the server. - -#$$ Server <-> modules - -The server makes use of a general API for communicating with -modules. The client is not required to communicate directly with -available modules. By abstracting the authentication interface, it -becomes possible for the local administrator to make a run time -decision about the authentication method adopted by the server. - -#$$$ Functions and definitions available to servers and modules - -[This section will document the following functions - - pam_set_item() - pam_get_item() - pam_fail_delay(pam_handle_t *pamh, unsigned int micro_sec) - pam_get_env(pam_handle_t *pamh, const char *varname) - pam_strerror(pam_handle_t *pamh, int pam_errno) - -Event driven support (XXX work in progress) - - pam_register_event() - app or module associates an event poller/handler - pam_select_event() - query for any outstanding event and act on any -] - -#$$$ Server <-> libpam - -[This section will document the following pam_ calls: - - pam_start - pam_end - pam_authenticate (*) - pam_setcred - pam_acct_mgmt - pam_open_session - pam_close_session - pam_chauthtok (*) - -The asterisked functions may return PAM_INCOMPLETE. In such cases, the -application should be aware that the conversation function was called -and that it returned PAM_CONV_AGAIN to a module. The correct action -for the application to take in response to receiving PAM_INCOMPLETE, -is to acquire the replies so that the next time the conversation -function is called it will be able to provide the desired -responses. And then recall pam_authenticate (pam_chauthtok) with the -same arguments. Libpam will arrange that the module stack is resumed -from the module that returned before. This functionality is required -for programs whose user interface is maintained by an event loop. ] - -#$$$ libpam <-> modules - -[This section will document the following pam_ and pam_sm_ calls: - -functions provided by libpam - - pam_set_data - pam_get_data - -functions provided to libpam by each module - - groups: - AUTHENTICATION - pam_sm_authenticate - pam_sm_setcred - ACCOUNT - pam_sm_acct_mgmt - SESSION - pam_sm_open_session - pam_sm_close_session - AUTHENTICATION TOKEN MANAGEMENT - pam_sm_chauthtok -] - -#$$$ The conversation function - -The server application, as part of its initialization of libpam, -provides a conversation function for use by modules and libpam. The -purpose of the conversation function is to enable direct communication -to the applicant ultimately via the client and selected agents. - -[ this section will contain a definition for the conversation - function, the conversation structure (appdata etc), and legitimate - return codes for the application supplied function. - - PAM_SUCCESS - ok conversation completed - PAM_CONV_ERR - conversation failed - PAM_CONV_AGAIN - application needs control to complete conv - PAM_CONV_RECONSIDER - application believes module should check if - it still needs to converse for this info - ] - -#$ Security considerations - -This document is devoted to standardizing authentication -infrastructure: everything in this document has implications for -security. - -#$ Contact - -The email list for discussing issues related to this document is -<pam-list@redhat.com>. - -#$ References - -[#{OSF_RFC_PAM}] OSF RFC 86.0, "Unified Login with Pluggable Authentication - Modules (PAM)", October 1995 - -[#{PAM_STD_AGENTIDS}] Definitions for standard agents, "REGISTERED - AGENTS AND THEIR AGENT-ID'S", to be found here: - -## http://www.kernel.org/pub/linux/libs/pam/pre/doc/std-agent-ids.txt ## - -#$ Author's Address - -Andrew G. Morgan -Email: morgan@kernel.org - -## $Id$ ## diff --git a/doc/specs/formatter/.cvsignore b/doc/specs/formatter/.cvsignore deleted file mode 100644 index 8af8c897..00000000 --- a/doc/specs/formatter/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -lex.yy.c -parse.tab.c -padout diff --git a/doc/specs/formatter/Makefile b/doc/specs/formatter/Makefile deleted file mode 100644 index d73258d7..00000000 --- a/doc/specs/formatter/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -LIBS=-lfl - -padout: parse.tab.o - $(CC) -o padout parse.tab.o $(LIBS) - -parse.tab.o: parse.tab.c lex.yy.c - $(CC) -c parse.tab.c - -parse.tab.c: parse.y - bison parse.y - -lex.yy.c: parse.lex - flex parse.lex - -clean: - rm -f parse.tab.o parse.tab.c lex.yy.c padout *~ core diff --git a/doc/specs/formatter/parse.lex b/doc/specs/formatter/parse.lex deleted file mode 100644 index 1d5c898e..00000000 --- a/doc/specs/formatter/parse.lex +++ /dev/null @@ -1,11 +0,0 @@ -%% - -\#[\$]+[a-zA-Z]*(\=[0-9]+)? return NEW_COUNTER; -\#\{[a-zA-Z][a-zA-Z0-9\_]*\} return LABEL; -\# return NO_INDENT; -\#\# return RIGHT; -\\\# return HASH; -[^\n] return CHAR; -[\n] return NEWLINE; - -%% diff --git a/doc/specs/formatter/parse.y b/doc/specs/formatter/parse.y deleted file mode 100644 index 6da47d17..00000000 --- a/doc/specs/formatter/parse.y +++ /dev/null @@ -1,293 +0,0 @@ - -%{ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define MAXLINE 1000 -#define INDENT_STRING " " -#define PAPER_WIDTH 74 - - int indent=0; - int line=1; - char *last_label=NULL; - - extern void yyerror(const char *x); - extern char *get_label(const char *label); - extern void set_label(const char *label, const char *target); - char *new_counter(const char *key); - -#include "lex.yy.c" - -%} - -%union { - int def; - char *string; -} - -%token NEW_COUNTER LABEL HASH CHAR NEWLINE NO_INDENT RIGHT -%type <string> stuff text - -%start doc - -%% - -doc: -| doc NEWLINE { - printf("\n"); - ++line; -} -| doc stuff NEWLINE { - if (strlen($2) > (PAPER_WIDTH-(indent ? strlen(INDENT_STRING):0))) { - yyerror("line too long"); - } - printf("%s%s\n", indent ? INDENT_STRING:"", $2); - free($2); - indent = 1; - ++line; -} -| doc stuff RIGHT stuff NEWLINE { - char fixed[PAPER_WIDTH+1]; - int len; - - len = PAPER_WIDTH-(strlen($2)+strlen($4)); - - if (len >= 0) { - memset(fixed, ' ', len); - fixed[len] = '\0'; - } else { - yyerror("line too wide"); - fixed[0] = '\0'; - } - printf("%s%s%s\n", $2, fixed, $4); - free($2); - free($4); - indent = 1; - ++line; -} -| doc stuff RIGHT stuff RIGHT stuff NEWLINE { - char fixed[PAPER_WIDTH+1]; - int len, l; - - len = PAPER_WIDTH-(strlen($2)+strlen($4)); - - if (len < 0) { - len = 0; - yyerror("line too wide"); - } - - l = len/2; - memset(fixed, ' ', l); - fixed[l] = '\0'; - printf("%s%s%s", $2, fixed, $4); - free($2); - free($4); - - l = (len+1)/2; - memset(fixed, ' ', l); - fixed[l] = '\0'; - printf("%s%s\n", fixed, $6); - free($6); - - indent = 1; - ++line; -} -| doc stuff RIGHT stuff RIGHT stuff NEWLINE { - char fixed[PAPER_WIDTH+1]; - int len, l; - - len = PAPER_WIDTH-(strlen($2)+strlen($4)); - - if (len < 0) { - len = 0; - yyerror("line too wide"); - } - - l = len/2; - memset(fixed, ' ', l); - fixed[l] = '\0'; - printf("%s%s%s", $2, fixed, $4); - free($2); - free($4); - - l = (len+1)/2; - memset(fixed, ' ', l); - fixed[l] = '\0'; - printf("%s%s\n", fixed, $6); - free($6); - - indent = 1; - ++line; -} -; - -stuff: { - $$ = strdup(""); -} -| stuff text { - $$ = malloc(strlen($1)+strlen($2)+1); - sprintf($$,"%s%s", $1, $2); - free($1); - free($2); -} -; - -text: CHAR { - $$ = strdup(yytext); -} -| text CHAR { - $$ = malloc(strlen($1)+2); - sprintf($$,"%s%s", $1, yytext); - free($1); -} -| NO_INDENT { - $$ = strdup(""); - indent = 0; -} -| HASH { - $$ = strdup("#"); -} -| LABEL { - if (($$ = get_label(yytext)) == NULL) { - set_label(yytext, last_label); - $$ = strdup(""); - } -} -| NEW_COUNTER { - $$ = new_counter(yytext); -} -; - -%% - -typedef struct node_s { - struct node_s *left, *right; - const char *key; - char *value; -} *node_t; - -node_t label_root = NULL; -node_t counter_root = NULL; - -const char *find_key(node_t root, const char *key) -{ - while (root) { - int cmp = strcmp(key, root->key); - - if (cmp > 0) { - root = root->right; - } else if (cmp) { - root = root->left; - } else { - return root->value; - } - } - return NULL; -} - -node_t set_key(node_t root, const char *key, const char *value) -{ - if (root) { - int cmp = strcmp(key, root->key); - if (cmp > 0) { - root->right = set_key(root->right, key, value); - } else if (cmp) { - root->left = set_key(root->left, key, value); - } else { - free(root->value); - root->value = strdup(value); - } - } else { - root = malloc(sizeof(struct node_s)); - root->right = root->left = NULL; - root->key = strdup(key); - root->value = strdup(value); - } - return root; -} - -void yyerror(const char *x) -{ - fprintf(stderr, "line %d: %s\n", line, x); -} - -char *get_label(const char *label) -{ - const char *found = find_key(label_root, label); - - if (found) { - return strdup(found); - } - return NULL; -} - -void set_label(const char *label, const char *target) -{ - if (target == NULL) { - yyerror("no hanging value for label"); - target = "<??>"; - } - label_root = set_key(label_root, label, target); -} - -char *new_counter(const char *key) -{ - int i=0, j, ndollars = 0; - const char *old; - char *new; - - if (key[i++] != '#') { - yyerror("bad index"); - return strdup("<???>"); - } - - while (key[i] == '$') { - ++ndollars; - ++i; - } - - key += i; - old = find_key(counter_root, key); - new = malloc(20*ndollars); - - if (old) { - for (j=0; ndollars > 1 && old[j]; ) { - if (old[j++] == '.' && --ndollars <= 0) { - break; - } - } - if (j) { - strncpy(new, old, j); - } - if (old[j]) { - i = atoi(old+j); - } else { - new[j++] = '.'; - i = 0; - } - } else { - j=0; - while (--ndollars > 0) { - new[j++] = '0'; - new[j++] = '.'; - } - i = 0; - } - new[j] = '\0'; - sprintf(new+j, "%d", ++i); - - counter_root = set_key(counter_root, key, new); - - if (last_label) { - free(last_label); - } - last_label = strdup(new); - - return new; -} - -main() -{ - yyparse(); -} diff --git a/doc/specs/rfc86.0.txt b/doc/specs/rfc86.0.txt deleted file mode 100644 index 6dd5e6ea..00000000 --- a/doc/specs/rfc86.0.txt +++ /dev/null @@ -1,1851 +0,0 @@ - - - - - - - - - Open Software Foundation V. Samar (SunSoft) - Request For Comments: 86.0 R. Schemers (SunSoft) - October 1995 - - - - UNIFIED LOGIN WITH - PLUGGABLE AUTHENTICATION MODULES (PAM) - - - 1. INTRODUCTION - - Since low-level authentication mechanisms constantly evolve, it is - important to shield the high-level consumers of these mechanisms - (system-entry services and users) from such low-level changes. With - the Pluggable Authentication Module (PAM) framework, we can provide - pluggability for a variety of system-entry services -- not just - system authentication _per se_, but also for account, session and - password management. PAM's ability to _stack_ authentication modules - can be used to integrate `login' with different authentication - mechanisms such as RSA, DCE, and Kerberos, and thus unify login - mechanisms. The PAM framework can also provide easy integration of - smart cards into the system. - - Modular design and pluggability have become important for users who - want ease of use. In the PC hardware arena, no one wants to set the - interrupt vector numbers or resolve the addressing conflict between - various devices. In the software arena, people also want to be able - to replace components easily for easy customization, maintenance, and - upgrades. - - Authentication software deserves special attention because - authentication forms a very critical component of any secure computer - system. The authentication infrastructure and its components may - have to be modified or replaced either because some deficiencies have - been found in the current algorithms, or because sites want to - enforce a different security policy than what was provided by the - system vendor. The replacement and modification should be done in - such a way that the user is not affected by these changes. - - The solution has to address not just how the applications use the new - authentication mechanisms in a generic fashion, but also how the user - will be authenticated to these mechanisms in a generic way. The - former is addressed by GSS-API [Linn 93], while this RFC addresses - the later; these two efforts are complementary to each other. - - Since most system-entry services (for example, `login', `dtlogin', - `rlogin', `ftp', `rsh') may want to be independent of the specific - authentication mechanisms used by the machine, it is important that - there be a framework for _plugging_ in various mechanisms. This - requires that the system applications use a standard API to interact - - - - Samar, Schemers Page 1 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - with the authentication services. If these system-entry services - remain independent of the actual mechanism used on that machine, the - system administrator can install suitable authentication modules - without requiring changes to these applications. - - For any security system to be successful, it has to be easy to use. - In the case of authentication, the single most important ease-of-use - characteristic is that the user should not be required to learn about - various ways of authentication and remember multiple passwords. - Ideally, there should be one all-encompassing authentication system - where there is only one password, but for heterogeneous sites, - multiple authentication mechanisms have to co-exist. The problem of - integrating multiple authentication mechanisms such as Kerberos - [Steiner 88], RSA [Rivest 78], and Diffie-Hellman [Diffie 76, Taylor - 88], is also referred to as _integrated login_, or _unified login_ - problem. Even if the user has to use multiple authentication - mechanisms, the user should not be forced to type multiple passwords. - Furthermore, the user should be able to use the new network identity - without taking any further actions. The key here is in modular - integration of the network authentication technologies with `login' - and other system-entry services. - - In this RFC we discuss the architecture and design of pluggable - authentication modules. This design gives the capability to use - field-replaceable authentication modules along with unified login - capability. It thus provides for both _pluggability_ and _ease-of- - use_. - - The RFC is organized as follows. We first motivate the need for a - generic way to authenticate the user by various system-entry services - within the operating system. We describe the goals and constraints - of the design. This leads to the architecture, description of the - interfaces, and _stacking_ of modules to get unified login - functionality. We then describe our experience with the design, and - end with a description of future work. - - - 2. OVERVIEW OF IDENTIFICATION AND AUTHENTICATION MECHANISMS - - An identification and authentication ("I&A") mechanism is used to - establish a user's identity the system (i.e., to a local machine's - operating system) and to other principals on the network. On a - typical UNIX system, there are various ports of entry into the - system, such as `login', `dtlogin', `rlogin', `ftp', `rsh', `su', and - `telnet'. In all cases, the user has to be identified and - authenticated before granting appropriate access rights to the user. - The user identification and authentication for all these entry points - needs to be coordinated to ensure a secure system. - - In most of the current UNIX systems, the login mechanism is based - upon verification of the password using the modified DES algorithm. - - - - Samar, Schemers Page 2 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - The security of the implementation assumes that the password cannot - be guessed, and that the password does not go over the wire in the - clear. These assumptions, however, are not universally valid. - Various programs are now available freely on the Internet that can - run dictionary attack against the encrypted password. Further, some - of the network services (for example, `rlogin', `ftp', `telnet') send - the password over in clear, and there are "sniffer" programs freely - available to steal these passwords. The classical assumptions may be - acceptable on a trusted network, but in an open environment there is - a need to use more restrictive and stronger authentication - mechanisms. Examples of such mechanisms include Kerberos, RSA, - Diffie-Hellman, one-time password [Skey 94], and challenge-response - based smart card authentication systems. Since this list will - continue to evolve, it is important that the system-entry services do - not have hard-coded dependencies on any of these authentication - mechanisms. - - - 3. DESIGN GOALS - - The goals of the PAM framework are as follows: - - (a) The system administrator should be able to choose the default - authentication mechanism for the machine. This can range from - a simple password-based mechanism to a biometric or a smart - card based system. - - (b) It should be possible to configure the user authentication - mechanism on a per application basis. For example, a site may - require S/Key password authentication for `telnet' access, - while allowing machine `login' sessions with just UNIX password - authentication. - - (c) The framework should support the display requirements of the - applications. For example, for a graphical login session such - as `dtlogin', the user name and the password may have to be - entered in a new window. For networking system-entry - applications such as `ftp' and `telnet', the user name and - password has to be transmitted over the network to the client - machine. - - (d) It should be possible to configure multiple authentication - protocols for each of those applications. For example, one may - want the users to get authenticated by both Kerberos and RSA - authentication systems. - - (e) The system administrator should be able to _stack_ multiple - user authentication mechanisms such that the user is - authenticated with all authentication protocols without - retyping the password. - - - - - Samar, Schemers Page 3 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - (f) The architecture should allow for multiple passwords if - necessary to achieve higher security for users with specific - security requirements. - - (g) The system-entry services should not be required to change when - the underlying mechanism changes. This can be very useful for - third-party developers because they often do not have the - source code for these services. - - (h) The architecture should provide for a _pluggable_ model for - system authentication, as well as for other related tasks such - as password, account, and session management. - - (i) For backward-compatibility reasons, the PAM API should support - the authentication requirements of the current system-entry - services. - - There are certain issues that the PAM framework does not specifically - address: - - (a) We focus only on providing a generic scheme through which users - use passwords to establish their identities to the machine. - Once the identity is established, how the identity is - communicated to other interested parties is outside the scope - of this design. There are efforts underway at IETF [Linn 93] - to develop a Generic Security Services Application Interface - (GSSAPI) that can be used by applications for secure and - authenticated communication without knowing the underlying - mechanism. - - (b) The _single-signon_ problem of securely transferring the - identity of the caller to a remote site is not addressed. For - example, the problem of delegating credentials from the - `rlogin' client to the other machine without typing the - password is not addressed by our work. We also do not address - the problem of sending the passwords over the network in the - clear. - - (c) We do not address the source of information obtained from the - "`getXbyY()'" family of calls (e.g., `getpwnam()'). Different - operating systems address this problem differently. For - example, Solaris uses the name service switch (NSS) to - determine the source of information for the "`getXbyY()'" - calls. It is expected that data which is stored in multiple - sources (such as passwd entries in NIS+ and the DCE registry) - is kept in sync using the appropriate commands (such as - `passwd_export'). - - - - - - - - Samar, Schemers Page 4 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - 4. OVERVIEW OF THE PAM FRAMEWORK - - We propose that the goals listed above can be met through a framework - in which authentication modules can be _plugged_ independently of the - application. We call this the _Pluggable Authentication Modules_ - (PAM) framework. - - The core components of the PAM framework are the authentication - library API (the front end) and the authentication mechanism-specific - modules (the back end), connected through the Service Provider - Interface (SPI). Applications write to the PAM API, while the - authentication-system providers write to the PAM SPI and supply the - back end modules that are independent of the application. - - ftp telnet login (Applications) - | | | - | | | - +--------+--------+ - | - +-----+-----+ - | PAM API | <-- pam.conf file - +-----+-----+ - | - +--------+--------+ - UNIX Kerberos Smart Cards (Mechanisms) - - Figure 1: The Basic PAM Architecture - - Figure 1 illustrates the relationship between the application, the - PAM library, and the authentication modules. Three applications - (`login', `telnet' and `ftp') are shown which use the PAM - authentication interfaces. When an application makes a call to the - PAM API, it loads the appropriate authentication module as determined - by the configuration file, `pam.conf'. The request is forwarded to - the underlying authentication module (for example, UNIX password, - Kerberos, smart cards) to perform the specified operation. The PAM - layer then returns the response from the authentication module to the - application. - - PAM unifies system authentication and access control for the system, - and allows plugging of associated authentication modules through well - defined interfaces. The plugging can be defined through various - means, one of which uses a configuration file, such as the one in - Table 1. For each of the system applications, the file specifies the - authentication module that should be loaded. In the example below, - `login' uses the UNIX password module, while `ftp' and `telnet' use - the S/Key module. - - - - - - - - Samar, Schemers Page 5 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - Table 1: A Simplified View of a Sample PAM Configuration File. - - service module_path - ------- ----------- - login pam_unix.so - ftp pam_skey.so - telnet pam_skey.so - - Authentication configuration is only one aspect of this interface. - Other critical components include account management, session - management, and password management. For example, the `login' - program may want to verify not only the password but also whether the - account has aged or expired. Generic interfaces also need to be - provided so that the password can be changed according to the - requirements of the module. Furthermore, the application may want to - log information about the current session as determined by the - module. - - Not all applications or services may need all of the above - components, and not each authentication module may need to provide - support for all of the interfaces. For example, while `login' may - need access to all four components, `su' may need access to just the - authentication component. Some applications may use some specific - authentication and password management modules but share the account - and session management modules with others. - - This reasoning leads to a partitioning of the entire set of - interfaces into four areas of functionality: (1) authentication, (2) - account, (3) session, and (4) password. The concept of PAM was - extended to these functional areas by implementing each of them as a - separate pluggable module. - - Breaking the functionality into four modules helps the module - providers because they can use the system-provided libraries for the - modules that they are not changing. For example, if a supplier wants - to provide a better version of Kerberos, they can just provide that - new authentication and password module, and reuse the existing ones - for account and session. - - 4.1. Module Description - - More details on specific API's are described in Appendix A. A brief - description of four modules follows: - - (a) Authentication management: This set includes the - `pam_authenticate()' function to authenticate the user, and the - `pam_setcred()' interface to set, refresh or destroy the user - credentials. - - (b) Account management: This set includes the `pam_acct_mgmt()' - function to check whether the authenticated user should be - - - - Samar, Schemers Page 6 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - given access to his/her account. This function can implement - account expiration and access hour restrictions. - - (c) Session management: This set includes the `pam_open_session()' - and `pam_close_session()' functions for session management and - accounting. For example, the system may want to store the - total time for the session. - - (d) Password management: This set includes a function, - `pam_chauthtok()', to change the password. - - - 5. FRAMEWORK INTERFACES - - The PAM framework further provides a set of administrative interfaces - to support the above modules and to provide for application-module - communication. There is no corresponding service provider interface - (SPI) for such functions. - - 5.1. Administrative Interfaces - - Each set of PAM transactions starts with `pam_start()' and ends with - the `pam_end()' function. The interfaces `pam_get_item()' and - `pam_set_item()' are used to read and write the state information - associated with the PAM transaction. - - If there is any error with any of the PAM interfaces, the error - message can be printed with `pam_strerror()'. - - 5.2. Application-Module Communication - - During application initialization, certain data such as the user name - is saved in the PAM framework layer through `pam_start()' so that it - can be used by the underlying modules. The application can also pass - opaque data to the module which the modules will pass back while - communicating with the user. - - 5.3. User-Module Communication - - The `pam_start()' function also passes conversation function that has - to be used by the underlying modules to read and write module - specific authentication information. For example, these functions - can be used to prompt the user for the password in a way determined - by the application. PAM can thus be used by graphical, non- - graphical, or networked applications. - - - - - - - - - - Samar, Schemers Page 7 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - 5.4. Inter-Module Communication - - Though the modules are independent, they can share certain common - information about the authentication session such as user name, - service name, password, and conversation function through the - `pam_get_item()' and `pam_set_item()' interfaces. These API's can - also be used by the application to change the state information after - having called `pam_start()' once. - - 5.5. Module State Information - - The PAM service modules may want to keep certain module-specific - state information about the session. The interfaces `pam_get_data()' - and `pam_set_data()' can be used by the service modules to access and - update module-specific information as needed from the PAM handle. - The modules can also attach a cleanup function with the data. The - cleanup function is executed when `pam_end()' is called to indicate - the end of the current authentication activity. - - Since the PAM modules are loaded upon demand, there is no direct - module initialization support in the PAM framework. If there are - certain initialization tasks that the PAM service modules have to do, - they should be done upon the first invocation. However, if there are - certain clean-up tasks to be done when the authentication session - ends, the modules should use `pam_set_data()' to specify the clean-up - functions, which would be called when `pam_end()' is called by the - application. - - - 6. MODULE CONFIGURATION MANAGEMENT - - Table 2 shows an example of a configuration file `pam.conf' with - support for authentication, session, account, and password management - modules. `login' has three entries: one each for authentication - processing, session management and account management. Each entry - specifies the module name that should be loaded for the given module - type. In this example, the `ftp' service uses the authentication and - session modules. Note that all services here share the same session - management module, while having different authentication modules. - - - - - - - - - - - - - - - - Samar, Schemers Page 8 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - Table 2: Configuration File (pam.conf) with Different Modules - and Control Flow - - service module_type control_flag module_path options - ------- ----------- ------------ ----------- ------- - login auth required pam_unix_auth.so nowarn - login session required pam_unix_session.so - login account required pam_unix_account.so - ftp auth required pam_skey_auth.so debug - ftp session required pam_unix_session.so - telnet session required pam_unix_session.so - login password required pam_unix_passwd.so - passwd password required pam_unix_passwd.so - OTHER auth required pam_unix_auth.so - OTHER session required pam_unix_session.so - OTHER account required pam_unix_account.so - - The first field, _service_, denotes the service (for example, - `login', `passwd', `rlogin'). The name `OTHER' indicates the module - used by all other applications that have not been specified in this - file. This name can also be used if all services have the same - requirements. In the example, since all the services use the same - session module, we could have replaced those lines with a single - `OTHER' line. - - The second field, _module_type_, indicates the type of the PAM - functional module. It can be one of `auth', `account', `session', or - `password' modules. - - The third field, _control_flag_ determines the behavior of stacking - multiple modules by specifying whether any particular module is - _required_, _sufficient_, or _optional_. The next section describes - stacking in more detail. - - The fourth field, _module_path_, specifies the location of the - module. The PAM framework loads this module upon demand to invoke - the required function. - - The fifth field, _options_, is used by the PAM framework layer to - pass module specific options to the modules. It is up to the module - to parse and interpret the options. This field can be used by the - modules to turn on debugging or to pass any module specific - parameters such as a timeout value. It is also used to support - unified login as described below. The options field can be used by - the system administrator to fine-tune the PAM modules. - - If any of the fields are invalid, or if a module is not found, that - line is ignored and the error is logged as a critical error via - `syslog(3)'. If no entries are found for the given module type, then - the PAM framework returns an error to the application. - - - - - Samar, Schemers Page 9 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - 7. INTEGRATING MULTIPLE AUTHENTICATION SERVICES WITH STACKING - - In the world of heterogeneous systems, the system administrator often - has to deal with the problem of integrating multiple authentication - mechanisms. The user is often required to know about the - authentication command of the new authentication module (for example, - `kinit', `dce_login') after logging into the system. This is not - user-friendly because it forces people to remember to type the new - command and enter the new password. This functionality should be - invisible instead of burdening the user with it. - - There are two problems to be addressed here: - - (a) Supporting multiple authentication mechanisms. - - (b) Providing unified login in the presence of multiple mechanisms. - - In the previous section, we described how one could replace the - default authentication module with any other module of choice. Now - we demonstrate how the same model can be extended to provide support - for multiple modules. - - 7.1. Design for Stacked Modules - - One possibility was to provide hard-coded rules in `login' or other - applications requiring authentication services [Adamson 95]. But - this becomes very specific to the particular combination of - authentication protocols, and also requires the source code of the - application. Digital's Security Integration Architecture [SIA 95] - addresses this problem by specifying the same list of authentication - modules for all applications. Since requirements for various - applications can vary, it is essential that the configuration be on a - per-application basis. - - To support multiple authentication mechanisms, the PAM framework was - extended to support _stacking_. When any API is called, the back - ends for the stacked modules are invoked in the order listed, and the - result returned to the caller. In Figure 2, the authentication - service of `login' is stacked and the user is authenticated by UNIX, - Kerberos, and RSA authentication mechanisms. Note that in this - example, there is no stacking for session or account management - modules. - - - - - - - - - - - - - Samar, Schemers Page 10 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - login - | - +--------+--------+ - | | | - session auth account - | | | - +--+--+ +--+--+ +--+--+ - | PAM | | PAM | | PAM | - +--+--+ +--+--+ +--+--+ - | | | - UNIX UNIX UNIX - session auth account - | - Kerberos - auth - | - RSA - auth - - Figure 2: Stacking With the PAM Architecture - - Stacking is specified through additional entries in the configuration - file shown earlier. As shown in Table 2, for each application (such - as `login') the configuration file can specify multiple mechanisms - that have to be invoked in the specified order. When mechanisms - fail, the _control_flag_ decides which error should be returned to - the application. Since the user should not know which authentication - module failed when a bad password was typed, the PAM framework - continues to call other authentication modules on the stack even on - failure. The semantics of the control flag are as follows: - - (a) `required': With this flag, the module failure results in the - PAM framework returning the error to the caller _after_ - executing all other modules on the stack. For the function to - be able to return success to the application all `required' - modules have to report success. This flag is normally set when - authentication by this module is a _must_. - - (b) `optional': With this flag, the PAM framework ignores the - module failure and continues with the processing of the next - module in sequence. This flag is used when the user is allowed - to login even if that particular module has failed. - - (c) `sufficient': With this flag, if the module succeeds the PAM - framework returns success to the application immediately - without trying any other modules. For failure cases, the - _sufficient_ modules are treated as `optional'. - - Table 3 shows a sample configuration file that stacks the `login' - command. Here the user is authenticated by UNIX, Kerberos, and RSA - authentication services. The `required' key word for _control_flag_ - - - - Samar, Schemers Page 11 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - enforces that the user is allowed to login only if he/she is - authenticated by _both_ UNIX and Kerberos services. RSA - authentication is optional by virtue of the `optional' key word in - the _control_flag_ field. The user can still log in even if RSA - authentication fails. - - Table 3: PAM Configuration File with Support for Stacking - - service module_type control_flag module_path options - ------- ----------- ------------ ----------- ------- - login auth required pam_unix.so debug - login auth required pam_kerb.so use_mapped_pass - login auth optional pam_rsa.so use_first_pass - - Table 4 illustrates the use of the sufficient flag for the `rlogin' - service. The Berkeley `rlogin' protocol specifies that if the remote - host is trusted (as specified in the `/etc/hosts.equiv' file or in - the `.rhosts' file in the home directory of the user), then the - `rlogin' daemon should not require the user to type the password. If - this is not the case, then the user is required to type the password. - Instead of hard coding this policy in the `rlogin' daemon, this can - be expressed with the `pam.conf' file in Table 4. The PAM module - `pam_rhosts_auth.so.1' implements the `.rhosts' policy described - above. If a site administrator wants to enable remote login with - only passwords, then the first line should be deleted. - - Table 4: PAM Configuration File for the rlogin service - - service module_type control_flag module_path options - ------- ----------- ------------ ----------- ------- - rlogin auth sufficient pam_rhosts_auth.so - rlogin auth required pam_unix.so - - 7.2. Password-Mapping - - Multiple authentication mechanisms on a machine can lead to multiple - passwords that users have to remember. One attractive solution from - the ease-of-use viewpoint is to use the same password for all - mechanisms. This, however, can also weaken the security because if - that password were to be compromised in any of the multiple - mechanisms, all mechanisms would be compromised at the same time. - Furthermore, different authentication mechanisms may have their own - distinctive password requirements in regards to its length, allowed - characters, time interval between updates, aging, locking, and so - forth. These requirements make it problematic to use the same - password for multiple authentication mechanisms. - - The solution we propose, while not precluding use of the same - password for every mechanism, allows for a different password for - each mechanism through what we call _password-mapping_. This - basically means using the user's _primary_ password to encrypt the - - - - Samar, Schemers Page 12 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - user's other (_secondary_) passwords, and storing these encrypted - passwords in a place where they are available to the user. Once the - primary password is verified, the authentication modules would obtain - the other passwords for their own mechanisms by decrypting the - mechanism-specific encrypted password with the primary password, and - passing it to the authentication service. The security of this - design for password-mapping assumes that the primary password is the - user's strongest password, in terms of its unguessability (length, - type and mix of characters used, etc.). - - If there is any error in password-mapping, or if the mapping does not - exist, the user will be prompted for the password by each - authentication module. - - To support password-mapping, the PAM framework saves the primary - password and provides it to stacked authentication modules. The - password is cleared out before the `pam_authenticate' function - returns. - - How the password is encrypted depends completely on the module - implementation. The encrypted secondary password (also called a - "mapped password") can be stored in a trusted or untrusted place, - such as a smart card, a local file, or a directory service. If the - encrypted passwords are stored in an untrusted publicly accessible - place, this does provide an intruder with opportunities for potential - dictionary attack. - - Though password-mapping is voluntary, it is recommended that all - module providers add support for the following four mapping options: - - (a) `use_first_pass': Use the same password used by the first - mechanism that asked for a password. The module should not ask - for the password if the user cannot be authenticated by the - first password. This option is normally used when the system - administrator wants to enforce the same password across - multiple modules. - - (b) `try_first_pass': This is the same as `use_first_pass', except - that if the primary password is not valid, it should prompt the - user for the password. - - (c) `use_mapped_pass': Use the password-mapping scheme to get the - actual password for this module. One possible implementation - is to get the mapped-password using the XFN API [XFN 94], and - decrypt it with the primary password to get the module-specific - password. The module should not ask for the password if the - user cannot be authenticated by the first password. The XFN - API allows user-defined attributes (such as _mapped-password_) - to be stored in the _user-context_. Using the XFN API is - particularly attractive because support for the XFN may be - found on many systems in the future. - - - - Samar, Schemers Page 13 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - (d) `try_mapped_pass': This is the same as `use_mapped_pass', - except that if the primary password is not valid, it should - prompt the user for the password. - - When passwords get updated, the PAM framework stores both the old as - well as the new password to be able to inform other dependent - authentication modules about the change. Other modules can use this - information to update the encrypted password without forcing the user - to type the sequence of passwords again. The PAM framework clears - out the passwords before returning to the application. - - Table 3 illustrates how the same password can be used by `login' for - authenticating to the standard UNIX login, Kerberos and RSA services. - Once the user has been authenticated to the primary authentication - service (UNIX `login' in this example) with the primary password, the - option `use_mapped_pass' indicates to the Kerberos module that it - should use the primary password to decrypt the stored Kerberos - password and then use the Kerberos password to get the ticket for the - ticket-granting-service. After that succeeds, the option - `use_first_pass' indicates to the RSA module that instead of - prompting the user for a password, it should use the primary password - typed earlier for authenticating the user. Note that in this - scenario, the user has to enter the password just once. - - Note that if a one-time password scheme (e.g., S/Key) is used, - password mapping cannot apply. - - 7.3. Implications of Stacking on the PAM Design - - Because of the stacking capability of PAM, we have designed the PAM - API's to not return any data to the application, except status. If - this were not the case, it would be difficult for the PAM framework - to decide which module should return data to the application. When - there is any error, the application does not know which of the - modules failed. This behavior enables (even requires) the - application to be completely independent from the modules. - - Another design decision we have made is that PAM gives only the user - name to all the underlying PAM modules, hence it is the - responsibility of the PAM modules to convert the name to their own - internal format. For example, the Kerberos module may have to - convert the UNIX user name to a Kerberos principal name. - - Stacking also forces the modules to be designed such that they can - occur anywhere in the stack without any side-effects. - - Since modules such as the authentication and the password module are - very closely related, it is important they be configured in the same - order and with compatible options. - - - - - - Samar, Schemers Page 14 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - 8. INTEGRATION WITH SMART CARDS - - Many networking authentication protocols require possession of a long - key to establish the user identity. For ease-of-use reasons, that - long key is normally encrypted with the user's password so that the - user is not required to memorize it. However, weak passwords can be - compromised through a dictionary attack and thus undermine the - stronger network authentication mechanism. Furthermore, the - encrypted data is normally stored in a centrally accessible service - whose availability depends upon the reliability of the associated - service. Solutions have been proposed to use a pass-phrase or one- - time-password, but those are much longer than the regular eight - character passwords traditionally used with UNIX `login'. This makes - the solution user-unfriendly because it requires longer strings to be - remembered and typed. - - For most authentication protocol implementations, the trust boundary - is the local machine. This assumption may not be valid in cases - where the user is mobile and has to use publicly available networked - computers. In such cases, it is required that the clear text of the - key or the password never be made available to the machine. - - Smart cards solve the above problems by reducing password exposure by - supporting a _two factor_ authentication mechanism: the first with - the possession of the card, and the second with the knowledge of the - PIN associated with the card. Not only can the smart cards be a - secure repository of multiple passwords, they can also provide the - encryption and authentication functions such that the long (private) - key is never exposed outside the card. - - The PAM framework allows for integrating smart cards to the system by - providing a smart card specific module for authentication. - Furthermore, the unified login problem is simplified because the - multiple passwords for various authentication mechanisms can be - stored on the smart card itself. This can be enabled by adding a - suitable key-word such as `use_smart_card' in the _options_ field. - - - 9. SECURITY ISSUES - - It is important to understand the impact of PAM on the security of - any system so that the site-administrator can make an informed - decision. - - (a) Sharing of passwords with multiple authentication mechanisms. - - If there are multiple authentication modules, one possibility - is to use the same password for all of them. If the password - for any of the multiple authentication system is compromised, - the user's password in all systems would be compromised. If - this is a concern, then multiple passwords might be considered - - - - Samar, Schemers Page 15 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - at the cost of ease-of-use. - - (b) Password-mapping. - - This technique of encrypting all other passwords with the - primary password assumes that it is lot more difficult to crack - the primary password and that reasonable steps have been taken - to ensure limited availability of the encrypted primary - password. If this is not done, an intruder could target the - primary password as the first point of dictionary attack. If - one of the other modules provide stronger security than the - password based security, the site would be negating the strong - security by using password-mapping. If this is a concern, then - multiple passwords might be considered at the cost of ease-of- - use. If smart cards are used, they obviate the need for - password-mapping completely. - - (c) Security of the configuration file. - - Since the policy file dictates how the user is authenticated, - this file should be protected from unauthorized modifications. - - (d) Stacking various PAM modules. - - The system administrator should fully understand the - implications of stacking various modules that will be installed - on the system and their respective orders and interactions. - The composition of various authentication modules should be - carefully examined. The trusted computing base of the machine - now includes the PAM modules. - - - 10. EXPERIENCE WITH PAM - - The PAM framework was first added in Solaris 2.3 release as a private - internal interface. PAM is currently being used by several system - entry applications such as `login', `passwd', `su', `dtlogin', - `rlogind', `rshd', `telnetd', `ftpd', `in.rexecd', `uucpd', `init', - `sac', and `ttymon'. We have found that PAM provides an excellent - framework to encapsulate the authentication-related tasks for the - entire system. The Solaris 2.3 PAM API's were hence enhanced and - simplified to support stacking. - - PAM modules have been developed for UNIX, DCE, Kerberos, S/Key, - remote user authentication, and dialpass authentication. Other PAM - modules are under development, and integration with smart cards is - being planned. - - Some third parties have used the PAM interface to extend the security - mechanisms offered by the Solaris environment. - - - - - Samar, Schemers Page 16 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - The PAM API has been accepted by Common Desktop Environment (CDE) - vendors as the API to be used for integrating the graphical interface - for login, `dtlogin' with multiple authentication mechanisms. - - - 11. FUTURE WORK - - Amongst the various components of PAM, the password component needs - to be carefully examined to see whether the stacking semantics are - particularly applicable, and how PAM should deal with partial - failures when changing passwords. - - The _control_flag_ of the configuration file can be extended to - include other semantics. For example, if the error is "name service - not available", one may want to retry. It is also possible to offer - semantics of "return success if any of the modules return success". - - In an earlier section, we had mentioned integration of smart cards - with PAM. Though we feel that integration should be straight forward - from the PAM architecture point of view, there may be some issues - with implementation because the interfaces to the smart cards have - not yet been standardized. - - One possible extension to PAM is to allow the passing of module- - specific data between applications and PAM modules. For example, the - `login' program likes to build its new environment from a select list - of variables, yet the DCE module needs the `KRB5CCNAME' variable to - be exported to the child process. For now we have modified the - `login' program to explicitly export the `KRB5CCNAME' variable. - - Administrative tools are needed to help system administrators modify - `pam.conf', and perform sanity checks on it (i.e., a `pam_check' - utility). - - - 12. CONCLUSION - - The PAM framework and the module interfaces provide pluggability for - user authentication, as well as for account, session and password - management. The PAM architecture can be used by `login' and by all - other system-entry services, and thus ensure that all entry points - for the system have been secured. This architecture enables - replacement and modification of authentication modules in the field - to secure the system against the newly found weaknesses without - changing any of the system services. - - The PAM framework can be used to integrate `login' and `dtlogin' with - different authentication mechanisms such as RSA and Kerberos. - Multiple authentication systems can be accessed with the same - password. The PAM framework also provides easy integration of smart - cards into the system. - - - - Samar, Schemers Page 17 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - PAM provides complementary functionality to GSS-API, in that it - provides mechanisms through which the user gets authenticated to any - new system-level authentication service on the machine. GSS-API then - uses the credentials for authenticated and secure communications with - other application-level service entities on the network. - - - 13. ACKNOWLEDGEMENTS - - PAM development has spanned several release cycles at SunSoft. - Shau-Ping Lo, Chuck Hickey, and Alex Choy did the first design and - implementation. Bill Shannon and Don Stephenson helped with the PAM - architecture. Rocky Wu prototyped stacking of multiple modules. - Paul Fronberg, Charlie Lai, and Roland Schemers made very significant - enhancements to the PAM interfaces and took the project to completion - within a very short time. Kathy Slattery wrote the PAM - documentation. John Perry integrated PAM within the CDE framework. - - - APPENDIX A. PAM API'S - - This appendix gives an informal description of the various interfaces - of PAM. Since the goal here is just for the reader to get a working - knowledge about the PAM interfaces, not all flags and options have - been fully defined and explained. The API's described here are - subject to change. - - The PAM Service Provider Interface is very similar to the PAM API, - except for one extra parameter to pass module-specific options to the - underlying modules. - - A.1. Framework Layer API's - - int - pam_start( - char *service_name, - char *user, - struct pam_conv *pam_conversation, - pam_handle_t **pamh - ); - - `pam_start()' is called to initiate an authentication transaction. - `pam_start()' takes as arguments the name of the service, the name of - the user to be authenticated, the address of the conversation - structure. `pamh' is later used as a handle for subsequent calls to - the PAM library. - - The PAM modules do not communicate directly with the user; instead - they rely on the application to perform all such interaction. The - application needs to provide the conversation functions, `conv()', - and associated application data pointers through a `pam_conv' - - - - Samar, Schemers Page 18 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - structure when it initiates an authentication transaction. The - module uses the `conv()' function to prompt the user for data, - display error messages, or text information. - - int - pam_end( - pam_handle_t *pamh, - int pam_status - ); - - `pam_end()' is called to terminate the PAM transaction as specified - by `pamh', and to free any storage area allocated by the PAM modules - with `pam_set_item()'. - - int - pam_set_item( - pam_handle_t *pamh, - int item_type, - void *item - ); - - int - pam_get_item( - pam_handle_t *pamh, - int item_type, - void **item); - - `pam_get_item()' and `pam_set_item()' allow the parameters specified - in the initial call to `pam_start()' to be read and updated. This is - useful when a particular parameter is not available when - `pam_start()' is called or must be modified after the initial call to - `pam_start()'. `pam_set_item()' is passed a pointer to the object, - `item', and its type, `item_type'. `pam_get_item()' is passed the - address of the pointer, `item', which is assigned the address of the - requested object. - - The `item_type' is one of the following: - - Table 5: Possible Values for Item_type - - Item Name Description - --------- ----------- - PAM_SERVICE The service name - PAM_USER The user name - PAM_TTY The tty name - PAM_RHOST The remote host name - PAM_CONV The pam_conv structure - PAM_AUTHTOK The authentication token (password) - PAM_OLDAUTHTOK The old authentication token - PAM_RUSER The remote user name - - - - - Samar, Schemers Page 19 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - Note that the values of `PAM_AUTHTOK' and `PAM_OLDAUTHTOK' are only - available to PAM modules and not to the applications. They are - explicitly cleared out by the framework before returning to the - application. - - char * - pam_strerror( - int errnum - ); - - `pam_strerror()' maps the error number to a PAM error message string, - and returns a pointer to that string. - - int - pam_set_data( - pam_handle_t *pamh, - char *module_data_name, - char *data, - (*cleanup)(pam_handle_t *pamh, char *data, - int error_status) - ); - - The `pam_set_data()' function stores module specific data within the - PAM handle. The `module_data_name' uniquely specifies the name to - which some data and cleanup callback function can be attached. The - cleanup function is called when `pam_end()' is invoked. - - int - pam_get_data( - pam_handle_t *pamh, - char *module_data_name, - void **datap - ); - - The `pam_get_data()' function obtains module-specific data from the - PAM handle stored previously by the `pam_get_data()' function. The - `module_data_name' uniquely specifies the name for which data has to - be obtained. This function is normally used to retrieve module - specific state information. - - A.2. Authentication API's - - int - pam_authenticate( - pam_handle_t *pamh, - int flags - ); - - The `pam_authenticate()' function is called to verify the identity of - the current user. The user is usually required to enter a password - or similar authentication token, depending upon the authentication - - - - Samar, Schemers Page 20 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - module configured with the system. The user in question is specified - by a prior call to `pam_start()', and is referenced by the - authentication handle, `pamh'. - - int - pam_setcred( - pam_handle_t *pamh, - int flags - ); - - The `pam_setcred()' function is called to set the credentials of the - current process associated with the authentication handle, `pamh'. - The actions that can be denoted through `flags' include credential - initialization, refresh, reinitialization and deletion. - - A.3. Account Management API - - int - pam_acct_mgmt( - pam_handle_t *pamh, - int flags - ); - - The function `pam_acct_mgmt()' is called to determine whether the - current user's account and password are valid. This typically - includes checking for password and account expiration, valid login - times, etc. The user in question is specified by a prior call to - `pam_start()', and is referenced by the authentication handle, - `pamh'. - - A.4. Session Management API's - - int - pam_open_session( - pam_handle_t *pamh, - int flags - ); - - `pam_open_session()' is called to inform the session modules that a - new session has been initialized. All programs which use PAM should - invoke `pam_open_session()' when beginning a new session. - - int - pam_close_session( - pam_handle_t *pamh, - int flags - ); - - Upon termination of this session, the `pam_close_session()' function - should be invoked to inform the underlying modules that the session - has terminated. - - - - Samar, Schemers Page 21 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - A.5. Password Management API's - - int - pam_chauthtok( - pam_handle_t *pamh, - int flags - ); - - `pam_chauthtok()' is called to change the authentication token - associated with the user referenced by the authentication handle - `pamh'. After the call, the authentication token of the user will be - changed in accordance with the authentication module configured on - the system. - - - APPENDIX B. SAMPLE PAM APPLICATION - - This appendix shows a sample `login' application which uses the PAM - API's. It is not meant to be a fully functional login program, as - some functionality has been left out in order to emphasize the use of - PAM API's. - - #include <security/pam_appl.h> - - static int login_conv(int num_msg, struct pam_message **msg, - struct pam_response **response, void *appdata_ptr); - - static struct pam_conv pam_conv = {login_conv, NULL}; - - static pam_handle_t *pamh; /* Authentication handle */ - - void - main(int argc, char *argv[], char **renvp) - { - - /* - * Call pam_start to initiate a PAM authentication operation - */ - - if ((pam_start("login", user_name, &pam_conv, &pamh)) - != PAM_SUCCESS) - login_exit(1); - - pam_set_item(pamh, PAM_TTY, ttyn); - pam_set_item(pamh, PAM_RHOST, remote_host); - - while (!authenticated && retry < MAX_RETRIES) { - status = pam_authenticate(pamh, 0); - authenticated = (status == PAM_SUCCESS); - } - - - - - Samar, Schemers Page 22 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - if (status != PAM_SUCCESS) { - fprintf(stderr,"error: %s\n", pam_strerror(status)); - login_exit(1); - } - - /* now check if the authenticated user is allowed to login. */ - - if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { - if (status == PAM_AUTHTOK_EXPIRED) { - status = pam_chauthtok(pamh, 0); - if (status != PAM_SUCCESS) - login_exit(1); - } else { - login_exit(1); - } - } - - /* - * call pam_open_session to open the authenticated session - * pam_close_session gets called by the process that - * cleans up the utmp entry (i.e., init) - */ - if (status = pam_open_session(pamh, 0) != PAM_SUCCESS) { - login_exit(status); - } - - /* set up the process credentials */ - setgid(pwd->pw_gid); - - /* - * Initialize the supplementary group access list. - * This should be done before pam_setcred because - * the PAM modules might add groups during the pam_setcred call - */ - initgroups(user_name, pwd->pw_gid); - - status = pam_setcred(pamh, PAM_ESTABLISH_CRED); - if (status != PAM_SUCCESS) { - login_exit(status); - } - - /* set the real (and effective) UID */ - setuid(pwd->pw_uid); - - pam_end(pamh, PAM_SUCCESS); /* Done using PAM */ - - /* - * Add DCE/Kerberos cred name, if any. - * XXX - The module specific stuff should be removed from login - * program eventually. This is better placed in DCE module and - * will be once PAM has routines for "exporting" environment - - - - Samar, Schemers Page 23 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - * variables. - */ - krb5p = getenv("KRB5CCNAME"); - if (krb5p != NULL) { - ENVSTRNCAT(krb5ccname, krb5p); - envinit[basicenv++] = krb5ccname; - } - environ = envinit; /* Switch to the new environment. */ - exec_the_shell(); - - /* All done */ - } - - /* - * login_exit - Call exit() and terminate. - * This function is here for PAM so cleanup can - * be done before the process exits. - */ - static void - login_exit(int exit_code) - { - if (pamh) - pam_end(pamh, PAM_ABORT); - exit(exit_code); - /*NOTREACHED*/ - } - - /* - * login_conv(): - * This is the conv (conversation) function called from - * a PAM authentication module to print error messages - * or garner information from the user. - */ - - static int - login_conv(int num_msg, struct pam_message **msg, - struct pam_response **response, void *appdata_ptr) - { - - while (num_msg--) { - switch (m->msg_style) { - - case PAM_PROMPT_ECHO_OFF: - r->resp = strdup(getpass(m->msg)); - break; - - case PAM_PROMPT_ECHO_ON: - (void) fputs(m->msg, stdout); - r->resp = malloc(PAM_MAX_RESP_SIZE); - fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); - /* add code here to remove \n from fputs */ - - - - Samar, Schemers Page 24 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - break; - - case PAM_ERROR_MSG: - (void) fputs(m->msg, stderr); - break; - - case PAM_TEXT_INFO: - (void) fputs(m->msg, stdout); - break; - - default: - /* add code here to log error message, etc */ - break; - } - } - return (PAM_SUCCESS); - } - - - APPENDIX C. DCE MODULE - - This appendix describes a sample implementation of a DCE PAM module. - In order to simplify the description, we do not address the issues - raised by password-mapping or stacking. The intent is to show which - DCE calls are being made by the DCE module. - - The `pam_sm_*()' functions implement the PAM SPI functions which are - called from the PAM API functions. - - C.1. DCE Authentication Management - - The algorithm for authenticating with DCE (not including error - checking, prompting for passwords, etc.) is as follows: - - pam_sm_authenticate() - { - sec_login_setup_identity(...); - pam_set_data(...); - sec_login_valid_and_cert_ident(...); - } - - pam_sm_setcred() - { - pam_get_data(...); - sec_login_set_context(...); - } - - The `pam_sm_authenticate()' function for DCE uses the - `pam_set_data()' and `pam_get_data()' functions to keep state (like - the `sec_login_handle_t' context) between calls. The following - cleanup function is also registered and gets called when `pam_end()' - - - - Samar, Schemers Page 25 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - is called: - - dce_cleanup() - { - if (/* PAM_SUCCESS and - sec_login_valid_and_cert_ident success */) { - sec_login_release_context(...); - } else { - sec_login_purge_context(...); - } - } - - If everything was successful we release the login context, but leave - the credentials file intact. If the status passed to `pam_end()' was - not `PAM_SUCCESS' (i.e., a required module failed) we purge the login - context which also removes the credentials file. - - C.2. DCE Account Management - - The algorithm for DCE account management is as follows: - - pam_sm_acct_mgmt() - { - pam_get_data(...); - sec_login_inquire_net_info(...); - /* check for expired password and account */ - sec_login_free_net_info(...); - } - - The `sec_login_inquire_net_info()' function is called to obtain - information about when the user's account and/or password are going - to expire. A warning message is displayed (using the conversation - function) if the user's account or password is going to expire in the - near future, or has expired. These warning messages can be disabled - using the `nowarn' option in the `pam.conf' file. - - C.3. DCE Session Management - - The DCE session management functions are currently empty. They could - be modified to optionally remove the DCE credentials file upon - logout, etc. - - C.4. DCE Password Management - - The algorithm for DCE password management is as follows: - - - - - - - - - - Samar, Schemers Page 26 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - pam_sm_chauthtok - { - sec_rgy_site_open(...); - sec_rgy_acct_lookup(...); - sec_rgy_acct_passwd(...); - sec_rgy_site_close(...); - } - - The `sec_rgy_acct_passwd()' function is called to change the user's - password in the DCE registry. - - - REFERENCES - - [Adamson 95] W. A. Adamson, J. Rees, and P. Honeyman, "Joining - Security Realms: A Single Login for Netware and - Kerberos", CITI Technical Report 95-1, Center for - Information Technology Integration, University of - Michigan, Ann Arbor, MI, February 1995. - - [Diffie 76] W. Diffie and M. E. Hellman, "New Directions in - Cryptography", IEEE Transactions on Information - Theory, November 1976. - - [Linn 93] J. Linn, "Generic Security Service Application - Programming Interface", Internet RFC 1508, 1509, 1993. - - [Rivest 78] R. L. Rivest, A. Shamir, and L. Adleman., "A Method - for Obtaining Digital Signatures and Pubic-key - Cryptosystems", Communications of the ACM, 21(2), - 1978. - - [SIA 95] "Digital UNIX Security", Digital Equipment - Corporation, Order Number AA-Q0R2C-TE, July 1995. - - [Skey 94] N. M. Haller, "The S/Key One-Time Password System", - ISOC Symposium on Network and Distributed Security, - 1994. - - [Steiner 88] J.G. Steiner, B. C. Neuman, and J. I. Schiller, - "Kerberos, An Authentication Service for Open Network - Systems", in Proceedings of the Winter USENIX - Conference, Dallas, Jan 1988. - - [Taylor 88] B. Taylor and D. Goldberg, "Secure Networking in the - Sun Environment", Sun Microsystems Technical Paper, - 1988. - - [XFN 94] "Federated Naming: the XFN Specifications", X/Open - Preliminary Specification, X/Open Document #P403, - ISBN:1-85912-045-8, X/Open Co. Ltd., July 1994. - - - - Samar, Schemers Page 27 - - - - - - - - OSF-RFC 86.0 PAM October 1995 - - - - AUTHOR'S ADDRESS - - Vipin Samar Internet email: vipin@eng.sun.com - SunSoft, Inc. Telephone: +1-415-336-1002 - 2550 Garcia Avenue - Mountain View, CA 94043 - USA - - Roland J. Schemers III Internet email: schemers@eng.sun.com - SunSoft, Inc. Telephone: +1-415-336-1035 - 2550 Garcia Avenue - Mountain View, CA 94043 - USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Samar, Schemers Page 28 - - - - - - diff --git a/doc/specs/std-agent-id.raw b/doc/specs/std-agent-id.raw deleted file mode 100644 index d5fbdd56..00000000 --- a/doc/specs/std-agent-id.raw +++ /dev/null @@ -1,95 +0,0 @@ -PAM working group ## A.G. Morgan - -## $Id$ ## - -## Pluggable Authentication Modules ## - -## REGISTERED AGENTS AND THEIR AGENT-ID'S ## - -#$ Purpose of this document - -#$$#{definition} Definition of an agent-id - -The most complete version of a "PAM agent-id" is contained in this -reference [#$R#{PAM_RFC2}]. A copy of a recent definition is -reproduced here for convenience. The reader is recommended to consult -reference [#{PAM_RFC2}] for definitions of other terms that are -used in this document. - -## -------------- ## - -The agent_id is a sequence of characters satisfying the following -regexp: - - /^[a-z0-9\_]+(@[a-z0-9\_.]+)?$/ - -and has a specific form for each independent agent. - -o Agent_ids that do not contain an at-sign (@) are to be considered as - representing some authentication mode that is a "public - standard". Registered names MUST NOT contain an at-sign (@). - -o Anyone can define additional agents by using names in the format - name@domainname, e.g. "ouragent@example.com". The part following - the at-sign MUST be a valid fully qualified internet domain name - [RFC-1034] controlled by the person or organization defining the - name. (Said another way, if you control the email address that - your agent has as an identifier, they you are entitled to use - this identifier.) It is up to each domain how it manages its local - namespace. - -## -------------- ## - -#$ Registered agent-id's - -The structure of this section is a single subsection for each -registered agent-id. This section includes a full definition of binary -prompts accepted by the agent and example responses of said -agent. Using the defining section alone, it should be possible for a -third party to create a conforming agent and modules that can -interoperate with other implementations of these objects. - -*$ "userpass" - the user+password agent - -Many legacy authentication systems are hardcoded to support one and -only one authentication method. Namely, - - username: joe - password: <secret> - -Indeed, this authentication method is often embedded into parts of the -transport protocol. The "user+password" agent with PAM agent-id: - - "userpass" - -Is intended to support this legacy authentication scheme. The protocol -for binary prompt exchange with this 'standard agent' is as follows: - -Case 1: module does not know the username, but expects the agent to - obtain this information and also the user's password: - - module: {LENGTH;PAM_BP_SELECT;userpass;'/'} - agent: {} - -Case 2: module has suggested username, but would like agent to confirm - it and gather password: - - module: {} - agent: {} - -Case 3: module knows username and will not permit the agent to change it: - - module: {} - agent: {} - -#$ References - -[#{PAM_RFC2}] Internet draft, "Pluggable Authentication Modules - (PAM)", available here: - -# http://linux.kernel.org/pub/linux/libs/pam/pre/doc/current-draft.txt # - -#$ Author's Address - -Andrew G. Morgan -Email: morgan@kernel.org diff --git a/doc/txts/.cvsignore b/doc/txts/.cvsignore deleted file mode 100644 index f35c3921..00000000 --- a/doc/txts/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -pam*.txt diff --git a/doc/txts/README b/doc/txts/README deleted file mode 100644 index 540b09b5..00000000 --- a/doc/txts/README +++ /dev/null @@ -1,3 +0,0 @@ -$Id$ - -This is a directory for text versions of the pam documentation diff --git a/dynamic/Makefile b/dynamic/Makefile deleted file mode 100644 index 09102af0..00000000 --- a/dynamic/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# -# $Id$ -# -# - -include ../Make.Rules - -ifeq ($(WITH_LIBDEBUG),yes) - LIBNAME=pamd -else - LIBNAME=pam -endif -VERSION=.$(MAJOR_REL) -MODIFICATION=.$(MINOR_REL) - -# --------------------------------------------- - -dummy: ../Make.Rules all - -# --------------------------------------------- - -# dynamic library names - -PAMSHOBJ = pam.so -PAMSHOBJMAJ = $(PAMSHOBJ)$(VERSION) - -DLIBOBJECTS = pam.o - -# --------------------------------------------- -## rules - -all: dirs $(PAMSHOBJ) ../Make.Rules - -dirs: -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) dynamic -endif -ifeq ($(STATIC_LIBPAM),yes) - $(MKDIR) static -endif - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -$(PAMSHOBJ): $(DLIBOBJECTS) -ifeq ($(USESONAME),yes) - $(LD_L) $(SOSWITCH) $(PAMSHOBJMAJ) -o $@ $+ $(LINKLIBS) -else - $(LD_L) -o $@ $(DLIBOBJECTS) $(LINKLIBS) -endif - -install: all - $(MKDIR) $(FAKEROOT)$(libdir) -ifeq ($(DYNAMIC_LIBPAM),yes) - $(INSTALL) -m $(SHLIBMODE) $(PAMSHOBJ) $(FAKEROOT)$(libdir)/$(PAMSHOBJ) - $(LDCONFIG) -endif - -remove: - rm -f $(FAKEROOT)$(libdir)/$(LIBPAM) - $(LDCONFIG) - -clean: - rm -f a.out core *~ static/*.o dynamic/*.o - rm -f *.a *.o *.so ./include/security/*~ - if [ -d dynamic ]; then rmdir dynamic ; fi - if [ -d static ]; then rmdir static ; fi diff --git a/dynamic/pam.c b/dynamic/pam.c deleted file mode 100644 index 6dd376c2..00000000 --- a/dynamic/pam.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * $Id$ - * - * If you want to dynamically load libpam using dlopen() or something, - * then dlopen( ' this shared object ' ); It takes care of exporting - * the right symbols to any modules loaded by libpam. - */ - -#include <stdio.h> -#include <dlfcn.h> -#include <security/pam_appl.h> -#include <security/_pam_macros.h> - -#ifndef LIBPAMPATH -#define LIBPAMPATH "/lib/libpam.so" -#endif - -static void *libpam_h = NULL; - -#define CONFIRM_PAM_FUNCTION(x, y, z, err) \ - do { \ - union { const void *tpointer; y (*fn) z ; } fptr; \ - fptr.tpointer = dlsym(libpam_h, #x); real_##x = fptr.fn; \ - if (real_##x == NULL) { \ - D(("unable to resolve '" #x "': %s", dlerror())); \ - return err; \ - } \ - } while (0) - - -extern void _init(void); - -void _init() -{ - if (libpam_h == NULL) { - libpam_h = dlopen(LIBPAMPATH, RTLD_GLOBAL|RTLD_NOW); - } -} - -extern void _fini(void); - -void _fini() -{ - if (libpam_h != NULL) { - dlclose(libpam_h); - } -} - -int pam_start(const char *service_name, const char *user, - const struct pam_conv *pam_conversation, - pam_handle_t **pamh) -{ - static int (*real_pam_start)(const char *, const char *, - const struct pam_conv *, - pam_handle_t **); - CONFIRM_PAM_FUNCTION(pam_start, int, (const char *, const char *, - const struct pam_conv *, - pam_handle_t **), PAM_ABORT); - return real_pam_start(service_name, user, pam_conversation, pamh); -} - -int pam_end(pam_handle_t *pamh, int pam_status) -{ - static int (*real_pam_end)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_end, int, (pam_handle_t *, int), PAM_ABORT); - return real_pam_end(pamh, pam_status); -} - -int pam_set_item(pam_handle_t *pamh, int item_type, const void *item) -{ - static int (*real_pam_set_item)(pam_handle_t *, int, const void *); - CONFIRM_PAM_FUNCTION(pam_set_item, int, - (pam_handle_t *, int, const void *), PAM_ABORT); - return real_pam_set_item(pamh, item_type, item); -} - -int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) -{ - static int (*real_pam_get_item)(const pam_handle_t *, int, const void **); - CONFIRM_PAM_FUNCTION(pam_get_item, int, - (const pam_handle_t *, int, const void **), - PAM_ABORT); - return real_pam_get_item(pamh, item_type, item); -} - -int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay) -{ - static int (*real_pam_fail_delay)(pam_handle_t *, unsigned int); - CONFIRM_PAM_FUNCTION(pam_fail_delay, int, (pam_handle_t *, unsigned int), - PAM_ABORT); - return real_pam_fail_delay(pamh, musec_delay); -} - -typedef const char * const_char_pointer; - -const_char_pointer pam_strerror(pam_handle_t *pamh, int errnum) -{ - static const_char_pointer (*real_pam_strerror)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_strerror, const_char_pointer, - (pam_handle_t *, int), NULL); - return real_pam_strerror(pamh, errnum); -} - -int pam_putenv(pam_handle_t *pamh, const char *name_value) -{ - static int (*real_pam_putenv)(pam_handle_t *, const char *); - CONFIRM_PAM_FUNCTION(pam_putenv, int, (pam_handle_t *, const char *), - PAM_ABORT); - return real_pam_putenv(pamh, name_value); -} - -const_char_pointer pam_getenv(pam_handle_t *pamh, const char *name) -{ - static const_char_pointer (*real_pam_getenv)(pam_handle_t *, const char *); - CONFIRM_PAM_FUNCTION(pam_getenv, const_char_pointer, - (pam_handle_t *, const char *), NULL); - return real_pam_getenv(pamh, name); -} - -typedef char ** char_ppointer; -char_ppointer pam_getenvlist(pam_handle_t *pamh) -{ - static char_ppointer (*real_pam_getenvlist)(pam_handle_t *); - CONFIRM_PAM_FUNCTION(pam_getenvlist, char_ppointer, (pam_handle_t *), - NULL); - return real_pam_getenvlist(pamh); -} - -/* Authentication management */ - -int pam_authenticate(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_authenticate)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_authenticate, int, (pam_handle_t *, int), - PAM_ABORT); - return real_pam_authenticate(pamh, flags); -} - -int pam_setcred(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_setcred)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_setcred, int, (pam_handle_t *, int), PAM_ABORT); - return real_pam_setcred(pamh, flags); -} - -/* Account Management API's */ - -int pam_acct_mgmt(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_acct_mgmt)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_acct_mgmt, int, (pam_handle_t *, int), PAM_ABORT); - return real_pam_acct_mgmt(pamh, flags); -} - -/* Session Management API's */ - -int pam_open_session(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_open_session)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_open_session, int, (pam_handle_t *, int), - PAM_ABORT); - return real_pam_open_session(pamh, flags); -} - -int pam_close_session(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_close_session)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_close_session, int, (pam_handle_t *, int), - PAM_ABORT); - return real_pam_close_session(pamh, flags); -} - -/* Password Management API's */ - -int pam_chauthtok(pam_handle_t *pamh, int flags) -{ - static int (*real_pam_chauthtok)(pam_handle_t *, int); - CONFIRM_PAM_FUNCTION(pam_chauthtok, int, (pam_handle_t *, int), PAM_ABORT); - return real_pam_chauthtok(pamh, flags); -} diff --git a/dynamic/test.c b/dynamic/test.c deleted file mode 100644 index 35496fe4..00000000 --- a/dynamic/test.c +++ /dev/null @@ -1,27 +0,0 @@ -#include <stdio.h> -#include <dlfcn.h> -#include <unistd.h> - -#include <security/pam_appl.h> -#include <security/pam_misc.h> - -int main(int argc, char **argv) -{ - void *handle; - - handle = dlopen("./pam.so", RTLD_NOW); - if (handle == NULL) { - fprintf(stderr, "failed to load pam.so: %s\n", dlerror()); - exit(1); - } - - /* handle->XXX points to each of the PAM functions */ - - - if (dlclose(handle)) { - fprintf(stderr, "failed to unload pam.so: %s\n", dlerror()); - exit(1); - } - - exit(0); -} diff --git a/examples/.cvsignore b/examples/.cvsignore deleted file mode 100644 index 2769a41e..00000000 --- a/examples/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -blank -xsh -check_user diff --git a/examples/Makefile b/examples/Makefile deleted file mode 100644 index 7cabccaa..00000000 --- a/examples/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# -# $Id$ -# - -include ../Make.Rules - -PROGS = blank xsh check_user -SRCS = blank.c xsh.c check_user.c -PROGSUID = - -ifeq ($(WITH_LIBDEBUG),yes) - LIBSUFFIX=d -else - LIBSUFFIX= -endif - -CFLAGS += -I$(absolute_srcdir)/libpam_misc/include - -LOADLIBES = -L$(absolute_objdir)/libpam -L$(absolute_objdir)/libpamc \ - -L$(absolute_objdir)/libpam_misc -lpam -lpam_misc - -ifeq ($(STATIC_LIBPAM),yes) - ifneq ($(DYNAMIC),) - CFLAGS += $(CC_STATIC) - LOADLIBES += $(LIBDL) - endif -endif - -all: $(PROGS) - -check_user: check_user.o - $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) - -blank: blank.o - $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) - -xsh: xsh.o - $(CC) $(CFLAGS) -o $@ $< $(LOADLIBES) - -clean: - rm -f *.a *.so *.o *~ $(PROGS) $(PROGSUID) - rm -f *.a *.out *.o *.so - -# note, the programs are test programs, they should not be -# installed on your system! - -install: all - if [ -n "$(PROGS)" ]; then cp $(PROGS) ../bin ; fi - if [ -n "$(PROGSUID)" ]; then \ - $(INSTALL) -m 4555 $(PROGSUID) ../bin ; fi - -remove: - cd ../bin ; rm -f $(PROGS) $(PROGSUID) - for x in $(PROGS) $(PROGSUID) ; do rm -f ../bin/$$x ; done diff --git a/examples/blank.c b/examples/blank.c deleted file mode 100644 index 9d51756e..00000000 --- a/examples/blank.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * $Id$ - */ - -/* Andrew Morgan (morgan@parc.power.net) -- a self contained `blank' - * application - * - * I am not very proud of this code. It makes use of a possibly ill- - * defined pamh pointer to call pam_strerror() with. The reason that - * I was sloppy with this is historical (pam_strerror, prior to 0.59, - * did not require a pamh argument) and if this program is used as a - * model for anything, I should wish that you will take this error into - * account. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include <security/pam_appl.h> -#include <security/pam_misc.h> - -/* ------ some local (static) functions ------- */ - -static void bail_out(pam_handle_t *pamh, int really, int code, const char *fn) -{ - fprintf(stderr,"==> called %s()\n got: `%s'\n", fn, - pam_strerror(pamh, code)); - if (really && code) - exit (1); -} - -/* ------ some static data objects ------- */ - -static struct pam_conv conv = { - misc_conv, - NULL -}; - -/* ------- the application itself -------- */ - -int main(int argc, char **argv) -{ - pam_handle_t *pamh=NULL; - char *username=NULL; - int retcode; - - /* did the user call with a username as an argument ? */ - - if (argc > 2) { - fprintf(stderr,"usage: %s [username]\n",argv[0]); - } else if (argc == 2) { - username = argv[1]; - } - - /* initialize the Linux-PAM library */ - retcode = pam_start("blank", username, &conv, &pamh); - bail_out(pamh,1,retcode,"pam_start"); - - /* test the environment stuff */ - { -#define MAXENV 15 - const char *greek[MAXENV] = { - "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon", - "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu", - "l=zeta", "h=", "d", "k=xi" - }; - char **env; - int i; - - for (i=0; i<MAXENV; ++i) { - retcode = pam_putenv(pamh,greek[i]); - bail_out(pamh,0,retcode,"pam_putenv"); - } - env = pam_getenvlist(pamh); - if (env) - env = pam_misc_drop_env(env); - else - fprintf(stderr,"???\n"); - fprintf(stderr,"a test: c=[%s], j=[%s]\n" - , pam_getenv(pamh, "c"), pam_getenv(pamh, "j")); - } - - /* to avoid using goto we abuse a loop here */ - for (;;) { - /* authenticate the user --- `0' here, could have been PAM_SILENT - * | PAM_DISALLOW_NULL_AUTHTOK */ - - retcode = pam_authenticate(pamh, 0); - bail_out(pamh,0,retcode,"pam_authenticate"); - - /* has the user proved themself valid? */ - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: invalid request\n",argv[0]); - break; - } - - /* the user is valid, but should they have access at this - time? */ - - retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ - bail_out(pamh,0,retcode,"pam_acct_mgmt"); - - if (retcode == PAM_NEW_AUTHTOK_REQD) { - fprintf(stderr,"Application must request new password...\n"); - retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); - bail_out(pamh,0,retcode,"pam_chauthtok"); - } - - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: invalid request\n",argv[0]); - break; - } - - /* `0' could be as above */ - retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); - bail_out(pamh,0,retcode,"pam_setcred1"); - - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem setting user credentials\n" - ,argv[0]); - break; - } - - /* open a session for the user --- `0' could be PAM_SILENT */ - retcode = pam_open_session(pamh,0); - bail_out(pamh,0,retcode,"pam_open_session"); - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem opening a session\n",argv[0]); - break; - } - - fprintf(stderr,"The user has been authenticated and `logged in'\n"); - - /* close a session for the user --- `0' could be PAM_SILENT - * it is possible that this pam_close_call is in another program.. - */ - - retcode = pam_close_session(pamh,0); - bail_out(pamh,0,retcode,"pam_close_session"); - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem closing a session\n",argv[0]); - break; - } - - retcode = pam_setcred(pamh, PAM_DELETE_CRED); - bail_out(pamh,0,retcode,"pam_setcred2"); - - break; /* don't go on for ever! */ - } - - /* close the Linux-PAM library */ - retcode = pam_end(pamh, PAM_SUCCESS); - pamh = NULL; - - bail_out(pamh,1,retcode,"pam_end"); - - exit(0); -} diff --git a/examples/check_user.c b/examples/check_user.c deleted file mode 100644 index 4a33f2a8..00000000 --- a/examples/check_user.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - $Id$ - - This program was contributed by Shane Watts <shane@icarus.bofh.asn.au> - slight modifications by AGM. - - You need to add the following (or equivalent) to the /etc/pam.conf file. - # check authorization - check auth required pam_unix_auth.so - check account required pam_unix_acct.so -*/ - -#include <security/pam_appl.h> -#include <security/pam_misc.h> -#include <stdio.h> - -static struct pam_conv conv = { - misc_conv, - NULL -}; - -int main(int argc, char *argv[]) -{ - pam_handle_t *pamh=NULL; - int retval; - const char *user="nobody"; - - if(argc == 2) { - user = argv[1]; - } - - if(argc > 2) { - fprintf(stderr, "Usage: check_user [username]\n"); - exit(1); - } - - retval = pam_start("check", user, &conv, &pamh); - - if (retval == PAM_SUCCESS) - retval = pam_authenticate(pamh, 0); /* is user really user? */ - - if (retval == PAM_SUCCESS) - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ - - /* This is where we have been authorized or not. */ - - if (retval == PAM_SUCCESS) { - fprintf(stdout, "Authenticated\n"); - } else { - fprintf(stdout, "Not Authenticated\n"); - } - - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ - pamh = NULL; - fprintf(stderr, "check_user: failed to release authenticator\n"); - exit(1); - } - - return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ -} diff --git a/examples/vpass.c b/examples/vpass.c deleted file mode 100644 index 9a07ee38..00000000 --- a/examples/vpass.c +++ /dev/null @@ -1,47 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <pwd.h> -#include <sys/types.h> -#include <security/pam_appl.h> - -static int test_conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr) -{ - return 0; -} - -static struct pam_conv conv = { - test_conv, - NULL -}; - -int main(void) -{ - char *user; - pam_handle_t *pamh; - struct passwd *pw; - uid_t uid; - int res; - - uid = geteuid(); - pw = getpwuid(uid); - if (pw) { - user = pw->pw_name; - } else { - fprintf(stderr, "Invalid userid: %d\n", uid); - exit(1); - } - - pam_start("vpass", user, &conv, &pamh); - pam_set_item(pamh, PAM_TTY, "/dev/tty"); - if ((res = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { - fprintf(stderr, "Oops: %s\n", pam_strerror(pamh, res)); - exit(1); - } - - pam_end(pamh, res); - exit(0); -} - - diff --git a/examples/wrap_xsh.sh b/examples/wrap_xsh.sh deleted file mode 100755 index af01697e..00000000 --- a/examples/wrap_xsh.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -export LD_PRELOAD=../libpam/libpam.so:../libpam_misc/libpam_misc.so -ldd ./xsh -./xsh "$@" - diff --git a/examples/xsh.c b/examples/xsh.c deleted file mode 100644 index fdbbbfd0..00000000 --- a/examples/xsh.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * $Id$ - */ - -/* Andrew Morgan (morgan@kernel.org) -- an example application - * that invokes a shell, based on blank.c */ - -#include <stdio.h> -#include <stdlib.h> - -#include <security/pam_appl.h> -#include <security/pam_misc.h> - -#include <security/_pam_aconf.h> - -#include <pwd.h> -#include <sys/types.h> -#include <unistd.h> - -/* ------ some local (static) functions ------- */ - -static void bail_out(pam_handle_t *pamh,int really, int code, const char *fn) -{ - fprintf(stderr,"==> called %s()\n got: `%s'\n", fn, - pam_strerror(pamh,code)); - if (really && code) - exit (1); -} - -/* ------ some static data objects ------- */ - -static struct pam_conv conv = { - misc_conv, - NULL -}; - -/* ------- the application itself -------- */ - -int main(int argc, char **argv) -{ - pam_handle_t *pamh=NULL; - const char *username=NULL; - const char *service="xsh"; - int retcode; - - /* did the user call with a username as an argument ? - * did they also */ - - if (argc > 3) { - fprintf(stderr,"usage: %s [username [service-name]]\n",argv[0]); - } - if ((argc >= 2) && (argv[1][0] != '-')) { - username = argv[1]; - } - if (argc == 3) { - service = argv[2]; - } - - /* initialize the Linux-PAM library */ - retcode = pam_start(service, username, &conv, &pamh); - bail_out(pamh,1,retcode,"pam_start"); - - /* fill in the RUSER and RHOST etc. fields */ - { - char buffer[100]; - struct passwd *pw; - const char *tty; - - pw = getpwuid(getuid()); - if (pw != NULL) { - retcode = pam_set_item(pamh, PAM_RUSER, pw->pw_name); - bail_out(pamh,1,retcode,"pam_set_item(PAM_RUSER)"); - } - - retcode = gethostname(buffer, sizeof(buffer)-1); - if (retcode) { - perror("failed to look up hostname"); - retcode = pam_end(pamh, PAM_ABORT); - bail_out(pamh,1,retcode,"pam_end"); - } - retcode = pam_set_item(pamh, PAM_RHOST, buffer); - bail_out(pamh,1,retcode,"pam_set_item(PAM_RHOST)"); - - tty = ttyname(fileno(stdin)); - if (tty) { - retcode = pam_set_item(pamh, PAM_TTY, tty); - bail_out(pamh,1,retcode,"pam_set_item(PAM_RHOST)"); - } - } - - /* to avoid using goto we abuse a loop here */ - for (;;) { - /* authenticate the user --- `0' here, could have been PAM_SILENT - * | PAM_DISALLOW_NULL_AUTHTOK */ - - retcode = pam_authenticate(pamh, 0); - bail_out(pamh,0,retcode,"pam_authenticate"); - - /* has the user proved themself valid? */ - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: invalid request\n",argv[0]); - break; - } - - /* the user is valid, but should they have access at this - time? */ - - retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ - bail_out(pamh,0,retcode,"pam_acct_mgmt"); - - if (retcode == PAM_NEW_AUTHTOK_REQD) { - fprintf(stderr,"Application must request new password...\n"); - retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); - bail_out(pamh,0,retcode,"pam_chauthtok"); - } - - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: invalid request\n",argv[0]); - break; - } - - /* `0' could be as above */ - retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); - bail_out(pamh,0,retcode,"pam_setcred"); - - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem setting user credentials\n" - ,argv[0]); - break; - } - - /* open a session for the user --- `0' could be PAM_SILENT */ - retcode = pam_open_session(pamh,0); - bail_out(pamh,0,retcode,"pam_open_session"); - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem opening a session\n",argv[0]); - break; - } - - pam_get_item(pamh, PAM_USER, (const void **) &username); - fprintf(stderr, - "The user [%s] has been authenticated and `logged in'\n", - username); - - /* this is always a really bad thing for security! */ - system("/bin/sh"); - - /* close a session for the user --- `0' could be PAM_SILENT - * it is possible that this pam_close_call is in another program.. - */ - - retcode = pam_close_session(pamh,0); - bail_out(pamh,0,retcode,"pam_close_session"); - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem closing a session\n",argv[0]); - break; - } - - /* `0' could be as above */ - retcode = pam_setcred(pamh, PAM_DELETE_CRED); - bail_out(pamh,0,retcode,"pam_setcred"); - if (retcode != PAM_SUCCESS) { - fprintf(stderr,"%s: problem deleting user credentials\n" - ,argv[0]); - break; - } - - break; /* don't go on for ever! */ - } - - /* close the Linux-PAM library */ - retcode = pam_end(pamh, PAM_SUCCESS); - pamh = NULL; - bail_out(pamh,1,retcode,"pam_end"); - - exit(0); -} diff --git a/libpam/.cvsignore b/libpam/.cvsignore deleted file mode 100644 index dd17fdcf..00000000 --- a/libpam/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -dynamic -static diff --git a/libpam/Makefile b/libpam/Makefile deleted file mode 100644 index cf49f627..00000000 --- a/libpam/Makefile +++ /dev/null @@ -1,151 +0,0 @@ -# -# $Id$ -# -# - -include ../Make.Rules - -# need to tell libpam about the default directory for PAMs -MOREFLAGS=-D"DEFAULT_MODULE_PATH=\"$(SECUREDIR)/\"" - -ifeq ($(WITH_LIBDEBUG),yes) - LIBNAME=libpamd -else - LIBNAME=libpam -endif -VERSION=.$(MAJOR_REL) -MODIFICATION=.$(MINOR_REL) - -# --------------------------------------------- - -dummy: ../Make.Rules all - -# --------------------------------------------- - -CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS) \ - -DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \ - -DLIBPAM_VERSION_MINOR=$(MINOR_REL) - -# dynamic library names - -LIBPAM = $(LIBNAME).$(DYNTYPE) -LIBPAMNAME = $(LIBPAM)$(VERSION) -LIBPAMFULL = $(LIBPAMNAME)$(MODIFICATION) - -# static library name - -LIBPAMSTATIC = $(LIBNAME).a - -ifdef STATIC -@echo Did you mean to set STATIC\? -MODULES = $(shell cat ../modules/_static_module_objects) -STATICOBJ = pam_static.o -else -MODULES = -endif - -ifeq ($(WITH_MEMORY_DEBUG),yes) -EXTRAS += pam_malloc.o -endif - -LIBOBJECTS = pam_item.o pam_strerror.o pam_end.o pam_start.o pam_data.o \ - pam_delay.o pam_dispatch.o pam_handlers.o pam_misc.o \ - pam_account.o pam_auth.o pam_session.o pam_password.o \ - pam_env.o pam_log.o $(EXTRAS) - -ifeq ($(DYNAMIC_LIBPAM),yes) -# libpam.so needs -ldl, too. -DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS) $(STATICOBJ)) -ifeq ($(STATICOBJ),yes) -dynamic/pam_static.o: pam_static.c ../modules/_static_module_objects - $(CC) $(CFLAGS) -c pam_static.c -o $@ -endif -endif - -ifeq ($(STATIC_LIBPAM),yes) -SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ)) -ifdef STATICOBJ -static/pam_static.o: pam_static.c ../modules/_static_module_objects - $(CC) $(CFLAGS) -c pam_static.c -o $@ -endif -endif - -# --------------------------------------------- -## rules - -all: dirs $(LIBPAM) $(LIBPAMSTATIC) ../Make.Rules - -dirs: -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) dynamic -endif -ifeq ($(STATIC_LIBPAM),yes) - $(MKDIR) static -endif - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -$(LIBPAM): $(DLIBOBJECTS) -ifeq ($(DYNAMIC_LIBPAM),yes) - ifeq ($(USESONAME),yes) - $(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) \ - $(MODULES) $(LINKLIBS) - else - $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) - endif - ifeq ($(NEEDSONAME),yes) - rm -f $(LIBPAMFULL) - ln -sf $(LIBPAM) $(LIBPAMFULL) - rm -f $(LIBPAMNAME) - ln -sf $(LIBPAM) $(LIBPAMNAME) - endif -endif - -$(LIBPAMSTATIC): $(SLIBOBJECTS) -ifeq ($(STATIC_LIBPAM),yes) - ar cr $@ $(SLIBOBJECTS) $(MODULES) - $(RANLIB) $@ -endif - -install: all - $(MKDIR) $(FAKEROOT)$(INCLUDED) $(FAKEROOT)$(libdir) - $(INSTALL) -m 644 include/security/pam_appl.h $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/pam_modules.h $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/_pam_macros.h $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/_pam_types.h $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/_pam_compat.h $(FAKEROOT)$(INCLUDED) -ifdef MEMORY_DEBUG - $(INSTALL) -m 644 include/security/pam_malloc.h $(FAKEROOT)$(INCLUDED) -endif -ifeq ($(DYNAMIC_LIBPAM),yes) - $(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(libdir)/$(LIBPAMFULL) - $(LDCONFIG) - ifneq ($(DYNTYPE),"sl") - ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBPAM) ; \ - ln -sf $(LIBPAMNAME) $(LIBPAM) ) - endif -endif -ifeq ($(STATIC_LIBPAM),yes) - $(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(libdir) -endif - -remove: - rm -f $(FAKEROOT)$(INCLUDED)/_pam_types.h - rm -f $(FAKEROOT)$(INCLUDED)/_pam_macros.h - rm -f $(FAKEROOT)$(INCLUDED)/pam_appl.h - rm -f $(FAKEROOT)$(INCLUDED)/pam_modules.h - rm -f $(FAKEROOT)$(INCLUDED)/pam_malloc.h - rm -f $(FAKEROOT)$(libdir)/$(LIBPAM).* - rm -f $(FAKEROOT)$(libdir)/$(LIBPAM) - $(LDCONFIG) - rm -f $(FAKEROOT)$(libdir)/$(LIBPAMSTATIC) - -clean: - rm -f a.out core *~ static/*.o dynamic/*.o - rm -f *.a *.o *.so ./include/security/*~ - if [ -d dynamic ]; then rmdir dynamic ; fi - if [ -d static ]; then rmdir static ; fi diff --git a/libpam/include/security/_pam_compat.h b/libpam/include/security/_pam_compat.h deleted file mode 100644 index a5f77e7a..00000000 --- a/libpam/include/security/_pam_compat.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _PAM_COMPAT_H -#define _PAM_COMPAT_H - -/* - * $Id$ - * - * This file was contributed by Derrick J Brashear <shadow@dementia.org> - * slight modification by Brad M. Garcia <bgarcia@fore.com> - * - * A number of operating systems have started to implement PAM. - * unfortunately, they have a different set of numeric values for - * certain constants. This file is included for compatibility's sake. - */ - -/* Solaris uses different constants. We redefine to those here */ -#if defined(solaris) || (defined(__SVR4) && defined(sun)) - -#ifndef _SECURITY__PAM_TYPES_H - -# ifdef _SECURITY_PAM_MODULES_H - -/* flags for pam_chauthtok() */ -# undef PAM_PRELIM_CHECK -# define PAM_PRELIM_CHECK 0x1 - -# undef PAM_UPDATE_AUTHTOK -# define PAM_UPDATE_AUTHTOK 0x2 - -# endif /* _SECURITY_PAM_MODULES_H */ - -#else /* _SECURITY__PAM_TYPES_H */ - -/* generic for pam_* functions */ -# undef PAM_SILENT -# define PAM_SILENT 0x80000000 - -/* flags for pam_setcred() */ -# undef PAM_ESTABLISH_CRED -# define PAM_ESTABLISH_CRED 0x1 - -# undef PAM_DELETE_CRED -# define PAM_DELETE_CRED 0x2 - -# undef PAM_REINITIALIZE_CRED -# define PAM_REINITIALIZE_CRED 0x4 - -# undef PAM_REFRESH_CRED -# define PAM_REFRESH_CRED 0x8 - -/* another binary incompatibility comes from the return codes! */ - -# undef PAM_CONV_ERR -# define PAM_CONV_ERR 6 - -# undef PAM_PERM_DENIED -# define PAM_PERM_DENIED 7 - -# undef PAM_MAXTRIES -# define PAM_MAXTRIES 8 - -# undef PAM_AUTH_ERR -# define PAM_AUTH_ERR 9 - -# undef PAM_NEW_AUTHTOK_REQD -# define PAM_NEW_AUTHTOK_REQD 10 - -# undef PAM_CRED_INSUFFICIENT -# define PAM_CRED_INSUFFICIENT 11 - -# undef PAM_AUTHINFO_UNAVAIL -# define PAM_AUTHINFO_UNAVAIL 12 - -# undef PAM_USER_UNKNOWN -# define PAM_USER_UNKNOWN 13 - -# undef PAM_CRED_UNAVAIL -# define PAM_CRED_UNAVAIL 14 - -# undef PAM_CRED_EXPIRED -# define PAM_CRED_EXPIRED 15 - -# undef PAM_CRED_ERR -# define PAM_CRED_ERR 16 - -# undef PAM_ACCT_EXPIRED -# define PAM_ACCT_EXPIRED 17 - -# undef PAM_AUTHTOK_EXPIRED -# define PAM_AUTHTOK_EXPIRED 18 - -# undef PAM_SESSION_ERR -# define PAM_SESSION_ERR 19 - -# undef PAM_AUTHTOK_ERR -# define PAM_AUTHTOK_ERR 20 - -# undef PAM_AUTHTOK_RECOVERY_ERR -# define PAM_AUTHTOK_RECOVERY_ERR 21 - -# undef PAM_AUTHTOK_LOCK_BUSY -# define PAM_AUTHTOK_LOCK_BUSY 22 - -# undef PAM_AUTHTOK_DISABLE_AGING -# define PAM_AUTHTOK_DISABLE_AGING 23 - -# undef PAM_NO_MODULE_DATA -# define PAM_NO_MODULE_DATA 24 - -# undef PAM_IGNORE -# define PAM_IGNORE 25 - -# undef PAM_ABORT -# define PAM_ABORT 26 - -# undef PAM_TRY_AGAIN -# define PAM_TRY_AGAIN 27 - -#endif /* _SECURITY__PAM_TYPES_H */ - -#endif /* defined(solaris) || (defined(__SVR4) && defined(sun)) */ - -#endif /* _PAM_COMPAT_H */ diff --git a/libpam/include/security/_pam_macros.h b/libpam/include/security/_pam_macros.h deleted file mode 100644 index 2827fabf..00000000 --- a/libpam/include/security/_pam_macros.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef PAM_MACROS_H -#define PAM_MACROS_H - -/* - * All kind of macros used by PAM, but usable in some other - * programs too. - * Organized by Cristian Gafton <gafton@redhat.com> - */ - -/* a 'safe' version of strdup */ - -#include <string.h> -#include <stdlib.h> - -#define x_strdup(s) ( (s) ? strdup(s):NULL ) - -/* Good policy to strike out passwords with some characters not just - free the memory */ - -#define _pam_overwrite(x) \ -do { \ - register char *__xx__; \ - if ((__xx__=(x))) \ - while (*__xx__) \ - *__xx__++ = '\0'; \ -} while (0) - -/* - * Don't just free it, forget it too. - */ - -#define _pam_drop(X) \ -do { \ - if (X) { \ - free(X); \ - X=NULL; \ - } \ -} while (0) - -#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \ -do { \ - int reply_i; \ - \ - for (reply_i=0; reply_i<replies; ++reply_i) { \ - if (reply[reply_i].resp) { \ - _pam_overwrite(reply[reply_i].resp); \ - free(reply[reply_i].resp); \ - } \ - } \ - if (reply) \ - free(reply); \ -} while (0) - -/* some debugging code */ - -#ifdef DEBUG - -/* - * This provides the necessary function to do debugging in PAM. - * Cristian Gafton <gafton@redhat.com> - */ - -#include <stdio.h> -#include <sys/types.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -/* - * This is for debugging purposes ONLY. DO NOT use on live systems !!! - * You have been warned :-) - CG - * - * to get automated debugging to the log file, it must be created manually. - * _PAM_LOGFILE must exist, mode 666 - */ - -#ifndef _PAM_LOGFILE -#define _PAM_LOGFILE "/tmp/pam-debug.log" -#endif - -static void _pam_output_debug_info(const char *file, const char *fn - , const int line) -{ - FILE *logfile; - int must_close = 1, fd; - -#ifdef O_NOFOLLOW - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { -#else - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { -#endif - if (!(logfile = fdopen(fd,"a"))) { - logfile = stderr; - must_close = 0; - close(fd); - } - } else { - logfile = stderr; - must_close = 0; - } - fprintf(logfile,"[%s:%s(%d)] ",file, fn, line); - fflush(logfile); - if (must_close) - fclose(logfile); -} - -static void _pam_output_debug(const char *format, ...) -{ - va_list args; - FILE *logfile; - int must_close = 1, fd; - - va_start(args, format); - -#ifdef O_NOFOLLOW - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { -#else - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { -#endif - if (!(logfile = fdopen(fd,"a"))) { - logfile = stderr; - must_close = 0; - close(fd); - } - } else { - logfile = stderr; - must_close = 0; - } - vfprintf(logfile, format, args); - fprintf(logfile, "\n"); - fflush(logfile); - if (must_close) - fclose(logfile); - - va_end(args); -} - -#define D(x) do { \ - _pam_output_debug_info(__FILE__, __FUNCTION__, __LINE__); \ - _pam_output_debug x ; \ -} while (0) - -#define _pam_show_mem(X,XS) do { \ - int i; \ - register unsigned char *x; \ - x = (unsigned char *)X; \ - fprintf(stderr, " <start at %p>\n", X); \ - for (i = 0; i < XS ; ++x, ++i) { \ - fprintf(stderr, " %02X. <%p:%02X>\n", i, x, *x); \ - } \ - fprintf(stderr, " <end for %p after %d bytes>\n", X, XS); \ -} while (0) - -#define _pam_show_reply(/* struct pam_response * */reply, /* int */replies) \ -do { \ - int reply_i; \ - setbuf(stderr, NULL); \ - fprintf(stderr, "array at %p of size %d\n",reply,replies); \ - fflush(stderr); \ - if (reply) { \ - for (reply_i = 0; reply_i < replies; reply_i++) { \ - fprintf(stderr, " elem# %d at %p: resp = %p, retcode = %d\n", \ - reply_i, reply+reply_i, reply[reply_i].resp, \ - reply[reply_i].resp, _retcode); \ - fflush(stderr); \ - if (reply[reply_i].resp) { \ - fprintf(stderr, " resp[%d] = '%s'\n", \ - strlen(reply[reply_i].resp), reply[reply_i].resp); \ - fflush(stderr); \ - } \ - } \ - } \ - fprintf(stderr, "done here\n"); \ - fflush(stderr); \ -} while (0) - -#else - -#define D(x) do { } while (0) -#define _pam_show_mem(X,XS) do { } while (0) -#define _pam_show_reply(reply, replies) do { } while (0) - -#endif /* DEBUG */ - -#endif /* PAM_MACROS_H */ diff --git a/libpam/include/security/_pam_types.h b/libpam/include/security/_pam_types.h deleted file mode 100644 index 871bfbf2..00000000 --- a/libpam/include/security/_pam_types.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * <security/_pam_types.h> - * - * $Id$ - * - * This file defines all of the types common to the Linux-PAM library - * applications and modules. - * - * Note, the copyright+license information is at end of file. - * - * Created: 1996/3/5 by AGM - */ - -#ifndef _SECURITY__PAM_TYPES_H -#define _SECURITY__PAM_TYPES_H - -#ifndef __LIBPAM_VERSION -# define __LIBPAM_VERSION __libpam_version -#endif -extern unsigned int __libpam_version; - -/* - * include local definition for POSIX - NULL - */ - -#include <locale.h> - -/* This is a blind structure; users aren't allowed to see inside a - * pam_handle_t, so we don't define struct pam_handle here. This is - * defined in a file private to the PAM library. (i.e., it's private - * to PAM service modules, too!) */ - -typedef struct pam_handle pam_handle_t; - -/* ----------------- The Linux-PAM return values ------------------ */ - -#define PAM_SUCCESS 0 /* Successful function return */ -#define PAM_OPEN_ERR 1 /* dlopen() failure when dynamically */ - /* loading a service module */ -#define PAM_SYMBOL_ERR 2 /* Symbol not found */ -#define PAM_SERVICE_ERR 3 /* Error in service module */ -#define PAM_SYSTEM_ERR 4 /* System error */ -#define PAM_BUF_ERR 5 /* Memory buffer error */ -#define PAM_PERM_DENIED 6 /* Permission denied */ -#define PAM_AUTH_ERR 7 /* Authentication failure */ -#define PAM_CRED_INSUFFICIENT 8 /* Can not access authentication data */ - /* due to insufficient credentials */ -#define PAM_AUTHINFO_UNAVAIL 9 /* Underlying authentication service */ - /* can not retrieve authenticaiton */ - /* information */ -#define PAM_USER_UNKNOWN 10 /* User not known to the underlying */ - /* authenticaiton module */ -#define PAM_MAXTRIES 11 /* An authentication service has */ - /* maintained a retry count which has */ - /* been reached. No further retries */ - /* should be attempted */ -#define PAM_NEW_AUTHTOK_REQD 12 /* New authentication token required. */ - /* This is normally returned if the */ - /* machine security policies require */ - /* that the password should be changed */ - /* beccause the password is NULL or it */ - /* has aged */ -#define PAM_ACCT_EXPIRED 13 /* User account has expired */ -#define PAM_SESSION_ERR 14 /* Can not make/remove an entry for */ - /* the specified session */ -#define PAM_CRED_UNAVAIL 15 /* Underlying authentication service */ - /* can not retrieve user credentials */ - /* unavailable */ -#define PAM_CRED_EXPIRED 16 /* User credentials expired */ -#define PAM_CRED_ERR 17 /* Failure setting user credentials */ -#define PAM_NO_MODULE_DATA 18 /* No module specific data is present */ -#define PAM_CONV_ERR 19 /* Conversation error */ -#define PAM_AUTHTOK_ERR 20 /* Authentication token manipulation error */ -#define PAM_AUTHTOK_RECOVER_ERR 21 /* Authentication information */ - /* cannot be recovered */ -#define PAM_AUTHTOK_LOCK_BUSY 22 /* Authentication token lock busy */ -#define PAM_AUTHTOK_DISABLE_AGING 23 /* Authentication token aging disabled */ -#define PAM_TRY_AGAIN 24 /* Preliminary check by password service */ -#define PAM_IGNORE 25 /* Ingore underlying account module */ - /* regardless of whether the control */ - /* flag is required, optional, or sufficient */ -#define PAM_ABORT 26 /* Critical error (?module fail now request) */ -#define PAM_AUTHTOK_EXPIRED 27 /* user's authentication token has expired */ -#define PAM_MODULE_UNKNOWN 28 /* module is not known */ - -#define PAM_BAD_ITEM 29 /* Bad item passed to pam_*_item() */ -#define PAM_CONV_AGAIN 30 /* conversation function is event driven - and data is not available yet */ -#define PAM_INCOMPLETE 31 /* please call this function again to - complete authentication stack. Before - calling again, verify that conversation - is completed */ - -/* - * Add new #define's here - take care to also extend the libpam code: - * pam_strerror() and "libpam/pam_tokens.h" . - */ - -#define _PAM_RETURN_VALUES 32 /* this is the number of return values */ - - -/* ---------------------- The Linux-PAM flags -------------------- */ - -/* Authentication service should not generate any messages */ -#define PAM_SILENT 0x8000U - -/* Note: these flags are used by pam_authenticate{,_secondary}() */ - -/* The authentication service should return PAM_AUTH_ERROR if the - * user has a null authentication token */ -#define PAM_DISALLOW_NULL_AUTHTOK 0x0001U - -/* Note: these flags are used for pam_setcred() */ - -/* Set user credentials for an authentication service */ -#define PAM_ESTABLISH_CRED 0x0002U - -/* Delete user credentials associated with an authentication service */ -#define PAM_DELETE_CRED 0x0004U - -/* Reinitialize user credentials */ -#define PAM_REINITIALIZE_CRED 0x0008U - -/* Extend lifetime of user credentials */ -#define PAM_REFRESH_CRED 0x0010U - -/* Note: these flags are used by pam_chauthtok */ - -/* The password service should only update those passwords that have - * aged. If this flag is not passed, the password service should - * update all passwords. */ -#define PAM_CHANGE_EXPIRED_AUTHTOK 0x0020U - -/* ------------------ The Linux-PAM item types ------------------- */ - -/* these defines are used by pam_set_item() and pam_get_item() */ - -#define PAM_SERVICE 1 /* The service name */ -#define PAM_USER 2 /* The user name */ -#define PAM_TTY 3 /* The tty name */ -#define PAM_RHOST 4 /* The remote host name */ -#define PAM_CONV 5 /* The pam_conv structure */ - -/* missing entries found in <security/pam_modules.h> for modules only! */ - -#define PAM_RUSER 8 /* The remote user name */ -#define PAM_USER_PROMPT 9 /* the prompt for getting a username */ -#define PAM_FAIL_DELAY 10 /* app supplied function to override failure - delays */ - -/* ---------- Common Linux-PAM application/module PI ----------- */ - -extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item); -extern int pam_get_item(const pam_handle_t *pamh, int item_type, - const void **item); -extern const char *pam_strerror(pam_handle_t *pamh, int errnum); - -extern int pam_putenv(pam_handle_t *pamh, const char *name_value); -extern const char *pam_getenv(pam_handle_t *pamh, const char *name); -extern char **pam_getenvlist(pam_handle_t *pamh); - -/* ---------- Common Linux-PAM application/module PI ----------- */ - -/* - * here are some proposed error status definitions for the - * 'error_status' argument used by the cleanup function associated - * with data items they should be logically OR'd with the error_status - * of the latest return from libpam -- new with .52 and positive - * impression from Sun although not official as of 1996/9/4 - * [generally the other flags are to be found in pam_modules.h] - */ - -#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */ - -/* - * here we define an externally (by apps or modules) callable function - * that primes the libpam library to delay when a stacked set of - * modules results in a failure. In the case of PAM_SUCCESS this delay - * is ignored. - * - * Note, the pam_[gs]et_item(... PAM_FAIL_DELAY ...) can be used to set - * a function pointer which can override the default fail-delay behavior. - * This item was added to accommodate event driven programs that need to - * manage delays more carefully. The function prototype for this data - * item is - * void (*fail_delay)(int status, unsigned int delay, void *appdata_ptr); - */ - -#define HAVE_PAM_FAIL_DELAY -extern int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay); - -#include <syslog.h> -#ifndef LOG_AUTHPRIV -# ifdef LOG_PRIV -# define LOG_AUTHPRIV LOG_PRIV -# endif /* LOG_PRIV */ -#endif /* !LOG_AUTHPRIV */ - -#ifdef MEMORY_DEBUG -/* - * this defines some macros that keep track of what memory has been - * allocated and indicates leakage etc... It should not be included in - * production application/modules. - */ -#include <security/pam_malloc.h> -#endif - -/* ------------ The Linux-PAM conversation structures ------------ */ - -/* Message styles */ - -#define PAM_PROMPT_ECHO_OFF 1 -#define PAM_PROMPT_ECHO_ON 2 -#define PAM_ERROR_MSG 3 -#define PAM_TEXT_INFO 4 - -/* Linux-PAM specific types */ - -#define PAM_RADIO_TYPE 5 /* yes/no/maybe conditionals */ - -/* This is for server client non-human interaction.. these are NOT - part of the X/Open PAM specification. */ - -#define PAM_BINARY_PROMPT 7 - -/* maximum size of messages/responses etc.. (these are mostly - arbitrary so Linux-PAM should handle longer values). */ - -#define PAM_MAX_NUM_MSG 32 -#define PAM_MAX_MSG_SIZE 512 -#define PAM_MAX_RESP_SIZE 512 - -/* Used to pass prompting text, error messages, or other informatory - * text to the user. This structure is allocated and freed by the PAM - * library (or loaded module). */ - -struct pam_message { - int msg_style; - const char *msg; -}; - -/* if the pam_message.msg_style = PAM_BINARY_PROMPT - the 'pam_message.msg' is a pointer to a 'const *' for the following - pseudo-structure. When used with a PAM_BINARY_PROMPT, the returned - pam_response.resp pointer points to an object with the following - structure: - - struct { - u32 length; # network byte order - unsigned char type; - unsigned char data[length-5]; - }; - - The 'libpamc' library is designed around this flavor of - message and should be used to handle this flavor of msg_style. - */ - -/* Used to return the user's response to the PAM library. This - structure is allocated by the application program, and free()'d by - the Linux-PAM library (or calling module). */ - -struct pam_response { - char *resp; - int resp_retcode; /* currently un-used, zero expected */ -}; - -/* The actual conversation structure itself */ - -struct pam_conv { - int (*conv)(int num_msg, const struct pam_message **msg, - struct pam_response **resp, void *appdata_ptr); - void *appdata_ptr; -}; - -#ifndef LINUX_PAM -/* - * the following few lines represent a hack. They are there to make - * the Linux-PAM headers more compatible with the Sun ones, which have a - * less strictly separated notion of module specific and application - * specific definitions. - */ -#include <security/pam_appl.h> -#include <security/pam_modules.h> -#endif - - -/* ... adapted from the pam_appl.h file created by Theodore Ts'o and - * - * Copyright Theodore Ts'o, 1996. All rights reserved. - * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org>, 1996-8 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#endif /* _SECURITY__PAM_TYPES_H */ - diff --git a/libpam/include/security/pam_appl.h b/libpam/include/security/pam_appl.h deleted file mode 100644 index b2eeb9f0..00000000 --- a/libpam/include/security/pam_appl.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * <security/pam_appl.h> - * - * This header file collects definitions for the PAM API --- that is, - * public interface between the PAM library and an application program - * that wishes to use it. - * - * Note, the copyright information is at end of file. - * - * Created: 15-Jan-96 by TYT - * Last modified: 1996/3/5 by AGM - * - * $Id$ - */ - -#ifndef _SECURITY_PAM_APPL_H -#define _SECURITY_PAM_APPL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <security/_pam_types.h> /* Linux-PAM common defined types */ - -/* -------------- The Linux-PAM Framework layer API ------------- */ - -extern int pam_start(const char *service_name, const char *user, - const struct pam_conv *pam_conversation, - pam_handle_t **pamh); -extern int pam_end(pam_handle_t *pamh, int pam_status); - -/* Authentication API's */ - -extern int pam_authenticate(pam_handle_t *pamh, int flags); -extern int pam_setcred(pam_handle_t *pamh, int flags); - -/* Account Management API's */ - -extern int pam_acct_mgmt(pam_handle_t *pamh, int flags); - -/* Session Management API's */ - -extern int pam_open_session(pam_handle_t *pamh, int flags); -extern int pam_close_session(pam_handle_t *pamh, int flags); - -/* Password Management API's */ - -extern int pam_chauthtok(pam_handle_t *pamh, int flags); - -#ifdef __cplusplus -} -#endif - -/* take care of any compatibility issues */ -#include <security/_pam_compat.h> - -/* - * Copyright Theodore Ts'o, 1996. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#endif /* _SECURITY_PAM_APPL_H */ diff --git a/libpam/include/security/pam_malloc.h b/libpam/include/security/pam_malloc.h deleted file mode 100644 index cc95d7de..00000000 --- a/libpam/include/security/pam_malloc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * $Id$ - */ - -/* - * This file (via the use of macros) defines a wrapper for the malloc - * family of calls. It logs where the memory was requested and also - * where it was free()'d and keeps a list of currently requested memory. - * - * It is hoped that it will provide some help in locating memory leaks. - */ - -#ifndef PAM_MALLOC_H -#define PAM_MALLOC_H - -/* these are the macro definitions for the stdlib.h memory functions */ - -#define malloc(s) pam_malloc(s,__FILE__,__FUNCTION__,__LINE__) -#define calloc(n,s) pam_calloc(n,s,__FILE__,__FUNCTION__,__LINE__) -#define free(x) pam_free(x,__FILE__,__FUNCTION__,__LINE__) -/* #define memalign(a,s) pam_memalign(a,s,__FILE__,__FUNCTION__,__LINE__) */ -#define realloc(x,s) pam_realloc(x,s,__FILE__,__FUNCTION__,__LINE__) -/* #define valloc(s) pam_valloc(s,__FILE__,__FUNCTION__,__LINE__) */ -/* #define alloca(s) pam_alloca(s,__FILE__,__FUNCTION__,__LINE__) */ -#define exit(i) pam_exit(i,__FILE__,__FUNCTION__,__LINE__) -#define strdup(s) pam_strdup(s,__FILE__,__FUNCTION__,__LINE__) - -/* these are the prototypes for the wrapper functions */ - -#include <sys/types.h> - -extern void *pam_malloc(size_t s,const char *,const char *, int); -extern void *pam_calloc(size_t n,size_t s,const char *,const char *, int); -extern void pam_free(void *x,const char *,const char *, int); -extern void *pam_memalign(size_t a,size_t s - ,const char *,const char *, int); -extern void *pam_realloc(void *x,size_t s,const char *,const char *, int); -extern void *pam_valloc(size_t s,const char *,const char *, int); -extern void *pam_alloca(size_t s,const char *,const char *, int); -extern void pam_exit(int i,const char *,const char *, int); -extern char *pam_strdup(const char *,const char *,const char *, int); - -/* these are the flags used to turn on and off diagnostics */ - -#define PAM_MALLOC_LEAKED 01 -#define PAM_MALLOC_REQUEST 02 -#define PAM_MALLOC_FREE 04 -#define PAM_MALLOC_EXCH (PAM_MALLOC_FREED|PAM_MALLOC_EXCH) -#define PAM_MALLOC_RESIZE 010 -#define PAM_MALLOC_FAIL 020 -#define PAM_MALLOC_NULL 040 -#define PAM_MALLOC_VERIFY 0100 -#define PAM_MALLOC_FUNC 0200 -#define PAM_MALLOC_PAUSE 0400 -#define PAM_MALLOC_STOP 01000 - -#define PAM_MALLOC_ALL 0777 - -#define PAM_MALLOC_DEFAULT \ - (PAM_MALLOC_LEAKED|PAM_MALLOC_PAUSE|PAM_MALLOC_FAIL) - -#include <stdio.h> - -extern FILE *pam_malloc_outfile; /* defaults to stdout */ - -/* how much output do you want? */ - -extern int pam_malloc_flags; -extern int pam_malloc_delay_length; /* how long to pause on errors */ - -#endif /* PAM_MALLOC_H */ diff --git a/libpam/include/security/pam_modules.h b/libpam/include/security/pam_modules.h deleted file mode 100644 index 4182ebd6..00000000 --- a/libpam/include/security/pam_modules.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * <security/pam_modules.h> - * - * $Id$ - * - */ - -#ifndef _SECURITY_PAM_MODULES_H -#define _SECURITY_PAM_MODULES_H - -#include <security/_pam_types.h> /* Linux-PAM common defined types */ - -/* these defines are used by pam_set_item() and pam_get_item() and are - * in addition to those found in <security/_pam_types.h> */ - -#define PAM_AUTHTOK 6 /* The authentication token (password) */ -#define PAM_OLDAUTHTOK 7 /* The old authentication token */ - -/* -------------- The Linux-PAM Module PI ------------- */ - -extern int pam_set_data(pam_handle_t *pamh, const char *module_data_name, - void *data, - void (*cleanup)(pam_handle_t *pamh, void *data, - int error_status)); -extern int pam_get_data(const pam_handle_t *pamh, - const char *module_data_name, const void **data); - -extern int pam_get_user(pam_handle_t *pamh, const char **user - , const char *prompt); - -#ifdef PAM_STATIC - -#define PAM_EXTERN static - -struct pam_module { - const char *name; /* Name of the module */ - - /* These are function pointers to the module's key functions. */ - - int (*pam_sm_authenticate)(pam_handle_t *pamh, int flags, - int argc, const char **argv); - int (*pam_sm_setcred)(pam_handle_t *pamh, int flags, - int argc, const char **argv); - int (*pam_sm_acct_mgmt)(pam_handle_t *pamh, int flags, - int argc, const char **argv); - int (*pam_sm_open_session)(pam_handle_t *pamh, int flags, - int argc, const char **argv); - int (*pam_sm_close_session)(pam_handle_t *pamh, int flags, - int argc, const char **argv); - int (*pam_sm_chauthtok)(pam_handle_t *pamh, int flags, - int argc, const char **argv); -}; - -#else /* !PAM_STATIC */ - -#define PAM_EXTERN extern - -#endif /* PAM_STATIC */ - -/* Lots of files include pam_modules.h that don't need these - * declared. However, when they are declared static, they - * need to be defined later. So we have to protect C files - * that include these without wanting these functions defined.. */ - -#if (defined(PAM_STATIC) && defined(PAM_SM_AUTH)) || !defined(PAM_STATIC) - -/* Authentication API's */ -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv); -PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char **argv); - -#endif /*(defined(PAM_STATIC) && defined(PAM_SM_AUTH)) - || !defined(PAM_STATIC)*/ - -#if (defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) || !defined(PAM_STATIC) - -/* Account Management API's */ -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv); - -#endif /*(defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) - || !defined(PAM_STATIC)*/ - -#if (defined(PAM_STATIC) && defined(PAM_SM_SESSION)) || !defined(PAM_STATIC) - -/* Session Management API's */ -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv); - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv); - -#endif /*(defined(PAM_STATIC) && defined(PAM_SM_SESSION)) - || !defined(PAM_STATIC)*/ - -#if (defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) || !defined(PAM_STATIC) - -/* Password Management API's */ -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv); - -#endif /*(defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) - || !defined(PAM_STATIC)*/ - -/* The following two flags are for use across the Linux-PAM/module - * interface only. The Application is not permitted to use these - * tokens. - * - * The password service should only perform preliminary checks. No - * passwords should be updated. */ -#define PAM_PRELIM_CHECK 0x4000 - -/* The password service should update passwords Note: PAM_PRELIM_CHECK - * and PAM_UPDATE_AUTHTOK cannot both be set simultaneously! */ -#define PAM_UPDATE_AUTHTOK 0x2000 - - -/* - * here are some proposed error status definitions for the - * 'error_status' argument used by the cleanup function associated - * with data items they should be logically OR'd with the error_status - * of the latest return from libpam -- new with .52 and positive - * impression from Sun although not official as of 1996/9/4 there are - * others in _pam_types.h -- they are for common module/app use. - */ - -#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */ - -/* take care of any compatibility issues */ -#include <security/_pam_compat.h> - -/* Copyright (C) Theodore Ts'o, 1996. - * Copyright (C) Andrew Morgan, 1996-8. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the - * GNU GPL are required INSTEAD OF the above restrictions. (This - * clause is necessary due to a potential bad interaction between the - * GNU GPL and the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#endif /* _SECURITY_PAM_MODULES_H */ - diff --git a/libpam/pam_account.c b/libpam/pam_account.c deleted file mode 100644 index 71e04f15..00000000 --- a/libpam/pam_account.c +++ /dev/null @@ -1,23 +0,0 @@ -/* pam_account.c - PAM Account Management */ - -#include <stdio.h> - -#include "pam_private.h" - -int pam_acct_mgmt(pam_handle_t *pamh, int flags) -{ - int retval; - - D(("called")); - - IF_NO_PAMH("pam_acct_mgmt", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT); - - return retval; -} diff --git a/libpam/pam_auth.c b/libpam/pam_auth.c deleted file mode 100644 index dbbdf00f..00000000 --- a/libpam/pam_auth.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * pam_auth.c -- PAM authentication - * - * $Id$ - * - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "pam_private.h" - -int pam_authenticate(pam_handle_t *pamh, int flags) -{ - int retval; - - D(("pam_authenticate called")); - - IF_NO_PAMH("pam_authenticate", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - if (pamh->former.choice == PAM_NOT_STACKED) { - _pam_sanitize(pamh); - _pam_start_timer(pamh); /* we try to make the time for a failure - independent of the time it takes to - fail */ - } - - retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE); - - if (retval != PAM_INCOMPLETE) { - _pam_sanitize(pamh); - _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ - D(("pam_authenticate exit")); - } else { - D(("will resume when ready")); - } - - return retval; -} - -int pam_setcred(pam_handle_t *pamh, int flags) -{ - int retval; - - D(("pam_setcred called")); - - IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - if (! flags) { - flags = PAM_ESTABLISH_CRED; - } - - retval = _pam_dispatch(pamh, flags, PAM_SETCRED); - - D(("pam_setcred exit")); - - return retval; -} diff --git a/libpam/pam_data.c b/libpam/pam_data.c deleted file mode 100644 index 06aa837f..00000000 --- a/libpam/pam_data.c +++ /dev/null @@ -1,123 +0,0 @@ -/* pam_data.c */ - -/* - * $Id$ - */ - -#include <stdlib.h> -#include <string.h> - -#include "pam_private.h" - -static struct pam_data *_pam_locate_data(const pam_handle_t *pamh, - const char *name) -{ - struct pam_data *data; - - D(("called")); - - IF_NO_PAMH("_pam_locate_data", pamh, NULL); - - data = pamh->data; - - while (data) { - if (!strcmp(data->name, name)) { - return data; - } - data = data->next; - } - - return NULL; -} - -int pam_set_data( - pam_handle_t *pamh, - const char *module_data_name, - void *data, - void (*cleanup)(pam_handle_t *pamh, void *data, int error_status)) -{ - struct pam_data *data_entry; - - D(("called")); - - IF_NO_PAMH("pam_set_data", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_APP(pamh)) { - D(("called from application!?")); - return PAM_SYSTEM_ERR; - } - - /* first check if there is some data already. If so clean it up */ - - if ((data_entry = _pam_locate_data(pamh, module_data_name))) { - if (data_entry->cleanup) { - data_entry->cleanup(pamh, data_entry->data, - PAM_DATA_REPLACE | PAM_SUCCESS ); - } - } else if ((data_entry = malloc(sizeof(*data_entry)))) { - char *tname; - - if ((tname = _pam_strdup(module_data_name)) == NULL) { - _pam_system_log(LOG_CRIT, "pam_set_data: no memory for data name"); - _pam_drop(data_entry); - return PAM_BUF_ERR; - } - data_entry->next = pamh->data; - pamh->data = data_entry; - data_entry->name = tname; - } else { - _pam_system_log(LOG_CRIT, "pam_set_data: cannot allocate data entry"); - return PAM_BUF_ERR; - } - - data_entry->data = data; /* note this could be NULL */ - data_entry->cleanup = cleanup; - - return PAM_SUCCESS; -} - -int pam_get_data( - const pam_handle_t *pamh, - const char *module_data_name, - const void **datap) -{ - struct pam_data *data; - - D(("called")); - - IF_NO_PAMH("pam_get_data", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_APP(pamh)) { - D(("called from application!?")); - return PAM_SYSTEM_ERR; - } - - data = _pam_locate_data(pamh, module_data_name); - if (data) { - *datap = data->data; - return PAM_SUCCESS; - } - - return PAM_NO_MODULE_DATA; -} - -void _pam_free_data(pam_handle_t *pamh, int status) -{ - struct pam_data *last; - struct pam_data *data; - - D(("called")); - - IF_NO_PAMH("_pam_free_data", pamh, /* no return value for void fn */); - data = pamh->data; - - while (data) { - last = data; - data = data->next; - if (last->cleanup) { - last->cleanup(pamh, last->data, status); - } - _pam_drop(last->name); - _pam_drop(last); - } -} diff --git a/libpam/pam_delay.c b/libpam/pam_delay.c deleted file mode 100644 index d38d47bc..00000000 --- a/libpam/pam_delay.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * pam_delay.c - * - * Copyright (c) Andrew G. Morgan <morgan@kernel.org> 1996-9 - * All rights reserved. - * - * $Id$ - * - */ - -/* - * This is a simple implementation of a delay on failure mechanism; an - * attempt to overcome authentication-time attacks in a simple manner. - */ - -#include <unistd.h> -#include <time.h> -#include "pam_private.h" - -/* ********************************************************************** - * initialize the time as unset, this is set on the return from the - * authenticating pair of of the libpam pam_XXX calls. - */ - -void _pam_reset_timer(pam_handle_t *pamh) -{ - D(("setting pamh->fail_delay.set to FALSE")); - pamh->fail_delay.set = PAM_FALSE; -} - -/* ********************************************************************** - * this function sets the start time for possible delayed failing. - * - * Eventually, it may set the timer so libpam knows how long the program - * has already been executing. Currently, this value is used to seed - * a pseudo-random number generator... - */ - -void _pam_start_timer(pam_handle_t *pamh) -{ - pamh->fail_delay.begin = time(NULL); - D(("starting timer...")); -} - -/* ******************************************************************* - * Compute a pseudo random time. The value is base*(1 +/- 1/5) where - * the distribution is pseudo gausian (the sum of three evenly - * distributed random numbers -- central limit theorem and all ;^) The - * linear random numbers are based on a formulae given in Knuth's - * Seminumerical recipies that was reproduced in `Numerical Recipies - * in C'. It is *not* a cryptographically strong generator, but it is - * probably "good enough" for our purposes here. - * - * /dev/random might be a better place to look for some numbers... - */ - -static unsigned int _pam_rand(unsigned int seed) -{ -#define N1 1664525 -#define N2 1013904223 - return N1*seed + N2; -} - -static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base) -{ - int i; - double sum; - unsigned int ans; - - for (sum=i=0; i<3; ++i) { - seed = _pam_rand(seed); - sum += (double) ((seed / 10) % 1000000); - } - sum = (sum/3.)/1e6 - .5; /* rescale */ - ans = (unsigned int) ( base*(1.+sum) ); - D(("random number: base=%u -> ans=%u\n", base, ans)); - - return ans; -} - -/* ********************************************************************** - * the following function sleeps for a random time. The actual time - * slept is computed above.. It is based on the requested time but will - * differ by up to +/- 25%. - */ - -void _pam_await_timer(pam_handle_t *pamh, int status) -{ - unsigned int delay; - D(("waiting?...")); - - delay = _pam_compute_delay(pamh->fail_delay.begin, - pamh->fail_delay.delay); - if (pamh->fail_delay.delay_fn_ptr) { - union { - const void *value; - void (*fn)(int, unsigned, void *); - } hack_fn_u; - void *appdata_ptr; - - if (pamh->pam_conversation) { - appdata_ptr = pamh->pam_conversation->appdata_ptr; - } else { - appdata_ptr = NULL; - } - - /* always call the applications delay function, even if - the delay is zero - indicate status */ - hack_fn_u.value = pamh->fail_delay.delay_fn_ptr; - hack_fn_u.fn(status, delay, appdata_ptr); - - } else if (status != PAM_SUCCESS && pamh->fail_delay.set) { - - D(("will wait %u usec", delay)); - - if (delay > 0) { - struct timeval tval; - - tval.tv_sec = delay / 1000000; - tval.tv_usec = delay % 1000000; - select(0, NULL, NULL, NULL, &tval); - } - } - - _pam_reset_timer(pamh); - D(("waiting done")); -} - -/* ********************************************************************** - * this function is known to both the module and the application, it - * keeps a running score of the largest-requested delay so far, as - * specified by either modules or an application. - */ - -int pam_fail_delay(pam_handle_t *pamh, unsigned int usec) -{ - unsigned int largest; - - IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR); - - D(("setting delay to %u",usec)); - - if (pamh->fail_delay.set) { - largest = pamh->fail_delay.delay; - } else { - pamh->fail_delay.set = PAM_TRUE; - largest = 0; - } - - D(("largest = %u",largest)); - - if (largest < usec) { - D(("resetting largest delay")); - pamh->fail_delay.delay = usec; - } - - return PAM_SUCCESS; -} - diff --git a/libpam/pam_dispatch.c b/libpam/pam_dispatch.c deleted file mode 100644 index 3ebdb5ba..00000000 --- a/libpam/pam_dispatch.c +++ /dev/null @@ -1,378 +0,0 @@ -/* pam_dispatch.c - handles module function dispatch */ - -/* - * Copyright (c) 1998 Andrew G. Morgan <morgan@kernel.org> - * - * $Id$ - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "pam_private.h" - -/* - * this is the return code we return when a function pointer is NULL - * or, the handler structure indicates a broken module config line - */ -#define PAM_MUST_FAIL_CODE PAM_PERM_DENIED - -/* impression codes - this gives some sense to the logical choices */ -#define _PAM_UNDEF 0 -#define _PAM_POSITIVE +1 -#define _PAM_NEGATIVE -1 - -/* frozen chain required codes */ -#define _PAM_PLEASE_FREEZE 0 -#define _PAM_MAY_BE_FROZEN 1 -#define _PAM_MUST_BE_FROZEN 2 - -/* - * walk a stack of modules. Interpret the administrator's instructions - * when combining the return code of each module. - */ - -static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h, - _pam_boolean resumed, int use_cached_chain) -{ - int depth, impression, status, skip_depth; - - IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR); - - if (h == NULL) { - const char *service=NULL; - - (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); - _pam_system_log(LOG_ERR, "no modules loaded for `%s' service", - service ? service:"<unknown>" ); - service = NULL; - return PAM_MUST_FAIL_CODE; - } - - /* if we are recalling this module stack because a former call did - not complete, we restore the state of play from pamh. */ - if (resumed) { - skip_depth = pamh->former.depth; - status = pamh->former.status; - impression = pamh->former.impression; - /* forget all that */ - pamh->former.impression = _PAM_UNDEF; - pamh->former.status = PAM_MUST_FAIL_CODE; - pamh->former.depth = 0; - } else { - skip_depth = 0; - impression = _PAM_UNDEF; - status = PAM_MUST_FAIL_CODE; - } - - /* Loop through module logic stack */ - for (depth=0 ; h != NULL ; h = h->next, ++depth) { - int retval, cached_retval, action; - - /* skip leading modules if they have already returned */ - if (depth < skip_depth) { - continue; - } - - /* attempt to call the module */ - if (h->func == NULL) { - D(("module function is not defined, indicating failure")); - retval = PAM_MODULE_UNKNOWN; - } else { - D(("passing control to module...")); - retval = h->func(pamh, flags, h->argc, h->argv); - D(("module returned: %s", pam_strerror(pamh, retval))); - if (h->must_fail) { - D(("module poorly listed in PAM config; forcing failure")); - retval = PAM_MUST_FAIL_CODE; - } - } - - /* - * PAM_INCOMPLETE return is special. It indicates that the - * module wants to wait for the application before continuing. - * In order to return this, the module will have saved its - * state so it can resume from an equivalent position when it - * is called next time. (This was added as of 0.65) - */ - if (retval == PAM_INCOMPLETE) { - pamh->former.impression = impression; - pamh->former.status = status; - pamh->former.depth = depth; - - D(("module %d returned PAM_INCOMPLETE", depth)); - return retval; - } - - /* - * use_cached_chain is how we ensure that the setcred/close_session - * and chauthtok(2) modules are called in the same order as they did - * when they were invoked as auth/open_session/chauthtok(1). This - * feature was added in 0.75 to make the behavior of pam_setcred - * sane. It was debugged by release 0.76. - */ - if (use_cached_chain != _PAM_PLEASE_FREEZE) { - - /* a former stack execution should have frozen the chain */ - - cached_retval = *(h->cached_retval_p); - if (cached_retval == _PAM_INVALID_RETVAL) { - - /* This may be a problem condition. It implies that - the application is running setcred, close_session, - chauthtok(2nd) without having first run - authenticate, open_session, chauthtok(1st) - [respectively]. */ - - D(("use_cached_chain is set to [%d]," - " but cached_retval == _PAM_INVALID_RETVAL", - use_cached_chain)); - - /* In the case of close_session and setcred there is a - backward compatibility reason for allowing this, in - the chauthtok case we have encountered a bug in - libpam! */ - - if (use_cached_chain == _PAM_MAY_BE_FROZEN) { - /* (not ideal) force non-frozen stack control. */ - cached_retval = retval; - } else { - D(("BUG in libpam -" - " chain is required to be frozen but isn't")); - - /* cached_retval is already _PAM_INVALID_RETVAL */ - } - } - } else { - /* this stack execution is defining the frozen chain */ - cached_retval = h->cached_retval = retval; - } - - /* verify that the return value is a valid one */ - if ((cached_retval < PAM_SUCCESS) - || (cached_retval >= _PAM_RETURN_VALUES)) { - - retval = PAM_MUST_FAIL_CODE; - action = _PAM_ACTION_BAD; - } else { - /* We treat the current retval with some respect. It may - (for example, in the case of setcred) have a value that - needs to be propagated to the user. We want to use the - cached_retval to determine the modules to be executed - in the stacked chain, but we want to treat each - non-ignored module in the cached chain as now being - 'required'. We only need to treat the, - _PAM_ACTION_IGNORE, _PAM_ACTION_IS_JUMP and - _PAM_ACTION_RESET actions specially. */ - - action = h->actions[cached_retval]; - } - - D(("use_cached_chain=%d action=%d cached_retval=%d retval=%d", - use_cached_chain, action, cached_retval, retval)); - - /* decide what to do */ - switch (action) { - case _PAM_ACTION_RESET: - - impression = _PAM_UNDEF; - status = PAM_MUST_FAIL_CODE; - break; - - case _PAM_ACTION_OK: - case _PAM_ACTION_DONE: - - if ( impression == _PAM_UNDEF - || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) { - impression = _PAM_POSITIVE; - status = retval; - } - if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) { - goto decision_made; - } - break; - - case _PAM_ACTION_BAD: - case _PAM_ACTION_DIE: -#ifdef PAM_FAIL_NOW_ON - if ( cached_retval == PAM_ABORT ) { - impression = _PAM_NEGATIVE; - status = PAM_PERM_DENIED; - goto decision_made; - } -#endif /* PAM_FAIL_NOW_ON */ - if ( impression != _PAM_NEGATIVE ) { - impression = _PAM_NEGATIVE; - status = retval; - } - if ( action == _PAM_ACTION_DIE ) { - goto decision_made; - } - break; - - case _PAM_ACTION_IGNORE: - break; - - /* if we get here, we expect action is a positive number -- - this is what the ...JUMP macro checks. */ - - default: - if ( _PAM_ACTION_IS_JUMP(action) ) { - - /* If we are evaluating a cached chain, we treat this - module as required (aka _PAM_ACTION_OK) as well as - executing the jump. */ - - if (use_cached_chain) { - if (impression == _PAM_UNDEF - || (impression == _PAM_POSITIVE - && status == PAM_SUCCESS) ) { - impression = _PAM_POSITIVE; - status = retval; - } - } - - /* this means that we need to skip #action stacked modules */ - do { - h = h->next; - } while ( --action > 0 && h != NULL ); - - /* note if we try to skip too many modules action is - still non-zero and we snag the next if. */ - } - - /* this case is a syntax error: we can't succeed */ - if (action) { - D(("action syntax error")); - impression = _PAM_NEGATIVE; - status = PAM_MUST_FAIL_CODE; - } - } - } - -decision_made: /* by getting here we have made a decision */ - - /* Sanity check */ - if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) { - D(("caught on sanity check -- this is probably a config error!")); - status = PAM_MUST_FAIL_CODE; - } - - /* We have made a decision about the modules executed */ - return status; -} - -/* - * This function translates the module dispatch request into a pointer - * to the stack of modules that will actually be run. the - * _pam_dispatch_aux() function (above) is responsible for walking the - * module stack. - */ - -int _pam_dispatch(pam_handle_t *pamh, int flags, int choice) -{ - struct handler *h = NULL; - int retval, use_cached_chain; - _pam_boolean resumed; - - IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from a module!?")); - return PAM_SYSTEM_ERR; - } - - /* Load all modules, resolve all symbols */ - - if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) { - _pam_system_log(LOG_ERR, "unable to dispatch function"); - return retval; - } - - use_cached_chain = _PAM_PLEASE_FREEZE; - - switch (choice) { - case PAM_AUTHENTICATE: - h = pamh->handlers.conf.authenticate; - break; - case PAM_SETCRED: - h = pamh->handlers.conf.setcred; - use_cached_chain = _PAM_MAY_BE_FROZEN; - break; - case PAM_ACCOUNT: - h = pamh->handlers.conf.acct_mgmt; - break; - case PAM_OPEN_SESSION: - h = pamh->handlers.conf.open_session; - break; - case PAM_CLOSE_SESSION: - h = pamh->handlers.conf.close_session; - use_cached_chain = _PAM_MAY_BE_FROZEN; - break; - case PAM_CHAUTHTOK: - h = pamh->handlers.conf.chauthtok; - if (flags & PAM_UPDATE_AUTHTOK) { - use_cached_chain = _PAM_MUST_BE_FROZEN; - } - break; - default: - _pam_system_log(LOG_ERR, "undefined fn choice; %d", choice); - return PAM_ABORT; - } - - if (h == NULL) { /* there was no handlers.conf... entry; will use - * handlers.other... */ - switch (choice) { - case PAM_AUTHENTICATE: - h = pamh->handlers.other.authenticate; - break; - case PAM_SETCRED: - h = pamh->handlers.other.setcred; - break; - case PAM_ACCOUNT: - h = pamh->handlers.other.acct_mgmt; - break; - case PAM_OPEN_SESSION: - h = pamh->handlers.other.open_session; - break; - case PAM_CLOSE_SESSION: - h = pamh->handlers.other.close_session; - break; - case PAM_CHAUTHTOK: - h = pamh->handlers.other.chauthtok; - break; - } - } - - /* Did a module return an "incomplete state" last time? */ - if (pamh->former.choice != PAM_NOT_STACKED) { - if (pamh->former.choice != choice) { - _pam_system_log(LOG_ERR, - "application failed to re-exec stack [%d:%d]", - pamh->former.choice, choice); - return PAM_ABORT; - } - resumed = PAM_TRUE; - } else { - resumed = PAM_FALSE; - } - - __PAM_TO_MODULE(pamh); - - /* call the list of module functions */ - retval = _pam_dispatch_aux(pamh, flags, h, resumed, use_cached_chain); - resumed = PAM_FALSE; - - __PAM_TO_APP(pamh); - - /* Should we recall where to resume next time? */ - if (retval == PAM_INCOMPLETE) { - D(("module [%d] returned PAM_INCOMPLETE")); - pamh->former.choice = choice; - } else { - pamh->former.choice = PAM_NOT_STACKED; - } - - return retval; -} - diff --git a/libpam/pam_end.c b/libpam/pam_end.c deleted file mode 100644 index 735da62e..00000000 --- a/libpam/pam_end.c +++ /dev/null @@ -1,77 +0,0 @@ -/* pam_end.c */ - -/* - * $Id$ - */ - -#include <stdlib.h> - -#include "pam_private.h" - -int pam_end(pam_handle_t *pamh, int pam_status) -{ - int ret; - - D(("entering pam_end()")); - - IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - /* first liberate the modules (it is not inconcevible that the - modules may need to use the service_name etc. to clean up) */ - - _pam_free_data(pamh, pam_status); - - /* now drop all modules */ - - if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) { - return ret; /* error occurred */ - } - - /* from this point we cannot call the modules any more. Free the remaining - memory used by the Linux-PAM interface */ - - _pam_drop_env(pamh); /* purge the environment */ - - _pam_overwrite(pamh->authtok); /* blank out old token */ - _pam_drop(pamh->authtok); - - _pam_overwrite(pamh->oldauthtok); /* blank out old token */ - _pam_drop(pamh->oldauthtok); - - _pam_overwrite(pamh->former.prompt); - _pam_drop(pamh->former.prompt); /* drop saved prompt */ - - _pam_overwrite(pamh->service_name); - _pam_drop(pamh->service_name); - - _pam_overwrite(pamh->user); - _pam_drop(pamh->user); - - _pam_overwrite(pamh->prompt); - _pam_drop(pamh->prompt); /* prompt for pam_get_user() */ - - _pam_overwrite(pamh->tty); - _pam_drop(pamh->tty); - - _pam_overwrite(pamh->rhost); - _pam_drop(pamh->rhost); - - _pam_overwrite(pamh->ruser); - _pam_drop(pamh->ruser); - - _pam_drop(pamh->pam_conversation); - pamh->fail_delay.delay_fn_ptr = NULL; - - /* and finally liberate the memory for the pam_handle structure */ - - _pam_drop(pamh); - - D(("exiting pam_end() successfully")); - - return PAM_SUCCESS; -} diff --git a/libpam/pam_env.c b/libpam/pam_env.c deleted file mode 100644 index 86a2889e..00000000 --- a/libpam/pam_env.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * pam_env.c - * - * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997 - * All rights reserved. - * - * This file was written from a "hint" provided by the people at SUN. - * and the X/Open XSSO draft of March 1997. - * - * $Id$ - */ - -#include <string.h> -#include <stdlib.h> -#ifdef sunos -#define memmove(x,y,z) bcopy(y,x,z) -#endif - -#include "pam_private.h" - -/* helper functions */ - -#ifdef DEBUG -static void _pam_dump_env(pam_handle_t *pamh) -{ - int i; - - D(("Listing environment of pamh=%p", pamh)); - D(("pamh->env = %p", pamh->env)); - D(("environment entries used = %d [of %d allocated]" - , pamh->env->requested, pamh->env->entries)); - - for (i=0; i<pamh->env->requested; ++i) { - _pam_output_debug(">%-3d [%9p]:[%s]" - , i, pamh->env->list[i], pamh->env->list[i]); - } - _pam_output_debug("*NOTE* the last item should be (nil)"); -} -#else -#define _pam_dump_env(x) -#endif - -/* - * Create the environment - */ - -int _pam_make_env(pam_handle_t *pamh) -{ - D(("called.")); - - IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT); - - /* - * get structure memory - */ - - pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ)); - if (pamh->env == NULL) { - _pam_system_log(LOG_CRIT, "_pam_make_env: out of memory"); - return PAM_BUF_ERR; - } - - /* - * get list memory - */ - - pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) ); - if (pamh->env->list == NULL) { - _pam_system_log(LOG_CRIT, "_pam_make_env: no memory for list"); - _pam_drop(pamh->env); - return PAM_BUF_ERR; - } - - /* - * fill entries in pamh->env - */ - - pamh->env->entries = PAM_ENV_CHUNK; - pamh->env->requested = 1; - pamh->env->list[0] = NULL; - - _pam_dump_env(pamh); /* only active when debugging */ - - return PAM_SUCCESS; -} - -/* - * purge the environment - */ - -void _pam_drop_env(pam_handle_t *pamh) -{ - D(("called.")); - IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */); - - if (pamh->env != NULL) { - int i; - /* we will only purge the pamh->env->requested number of elements */ - - for (i=pamh->env->requested-1; i-- > 0; ) { - D(("dropping #%3d>%s<", i, pamh->env->list[i])); - _pam_overwrite(pamh->env->list[i]); /* clean */ - _pam_drop(pamh->env->list[i]); /* forget */ - } - pamh->env->requested = 0; - pamh->env->entries = 0; - _pam_drop(pamh->env->list); /* forget */ - _pam_drop(pamh->env); /* forget */ - } else { - D(("no environment present in pamh?")); - } -} - -/* - * Return the item number of the given variable = first 'length' chars - * of 'name_value'. Since this is a static function, it is safe to - * assume its supplied arguments are well defined. - */ - -static int _pam_search_env(const struct pam_environ *env - , const char *name_value, int length) -{ - int i; - - for (i=env->requested-1; i-- > 0; ) { - if (strncmp(name_value,env->list[i],length) == 0 - && env->list[i][length] == '=') { - - return i; /* Got it! */ - - } - } - - return -1; /* no luck */ -} - -/* - * externally visible functions - */ - -/* - * pam_putenv(): Add/replace/delete a PAM-environment variable. - * - * Add/replace: - * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0") - * - * delete: - * name_value = "NAME" - */ - -int pam_putenv(pam_handle_t *pamh, const char *name_value) -{ - int l2eq, item, retval; - - D(("called.")); - IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT); - - if (name_value == NULL) { - _pam_system_log(LOG_ERR, "pam_putenv: no variable indicated"); - return PAM_PERM_DENIED; - } - - /* - * establish if we are setting or deleting; scan for '=' - */ - - for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq); - if (l2eq <= 0) { - _pam_system_log(LOG_ERR, "pam_putenv: bad variable"); - return PAM_BAD_ITEM; - } - - /* - * Look first for environment. - */ - - if (pamh->env == NULL || pamh->env->list == NULL) { - _pam_system_log(LOG_ERR, "pam_putenv: no env%s found", - pamh->env == NULL ? "":"-list"); - return PAM_ABORT; - } - - /* find the item to replace */ - - item = _pam_search_env(pamh->env, name_value, l2eq); - - if (name_value[l2eq]) { /* (re)setting */ - - if (item == -1) { /* new variable */ - D(("adding item: %s", name_value)); - /* enough space? */ - if (pamh->env->entries <= pamh->env->requested) { - register int i; - register char **tmp; - - /* get some new space */ - tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK - , sizeof(char *) ); - if (tmp == NULL) { - /* nothing has changed - old env intact */ - _pam_system_log(LOG_CRIT, - "pam_putenv: cannot grow environment"); - return PAM_BUF_ERR; - } - - /* copy old env-item pointers/forget old */ - for (i=0; i<pamh->env->requested; ++i) { - tmp[i] = pamh->env->list[i]; - pamh->env->list[i] = NULL; - } - - /* drop old list and replace with new */ - _pam_drop(pamh->env->list); - pamh->env->list = tmp; - pamh->env->entries += PAM_ENV_CHUNK; - - D(("resized env list")); - _pam_dump_env(pamh); /* only when debugging */ - } - - item = pamh->env->requested-1; /* old last item (NULL) */ - - /* add a new NULL entry at end; increase counter */ - pamh->env->list[pamh->env->requested++] = NULL; - - } else { /* replace old */ - D(("replacing item: %s\n with: %s" - , pamh->env->list[item], name_value)); - _pam_overwrite(pamh->env->list[item]); - _pam_drop(pamh->env->list[item]); - } - - /* - * now we have a place to put the new env-item, insert at 'item' - */ - - pamh->env->list[item] = _pam_strdup(name_value); - if (pamh->env->list[item] != NULL) { - _pam_dump_env(pamh); /* only when debugging */ - return PAM_SUCCESS; - } - - /* something went wrong; we should delete the item - fall through */ - - retval = PAM_BUF_ERR; /* an error occurred */ - } else { - retval = PAM_SUCCESS; /* we requested delete */ - } - - /* getting to here implies we are deleting an item */ - - if (item < 0) { - _pam_system_log(LOG_ERR, "pam_putenv: delete non-existent entry; %s", - name_value); - return PAM_BAD_ITEM; - } - - /* - * remove item: purge memory; reset counter; resize [; display-env] - */ - - D(("deleting: env#%3d:[%s]", item, pamh->env->list[item])); - _pam_overwrite(pamh->env->list[item]); - _pam_drop(pamh->env->list[item]); - --(pamh->env->requested); - D(("mmove: item[%d]+%d -> item[%d]" - , item+1, ( pamh->env->requested - item ), item)); - (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1] - , ( pamh->env->requested - item )*sizeof(char *) ); - - _pam_dump_env(pamh); /* only when debugging */ - - /* - * deleted. - */ - - return retval; -} - -/* - * Return the value of the requested environment variable - */ - -const char *pam_getenv(pam_handle_t *pamh, const char *name) -{ - int item; - - D(("called.")); - IF_NO_PAMH("pam_getenv", pamh, NULL); - - if (name == NULL) { - _pam_system_log(LOG_ERR, "pam_getenv: no variable indicated"); - return NULL; - } - - if (pamh->env == NULL || pamh->env->list == NULL) { - _pam_system_log(LOG_ERR, "pam_getenv: no env%s found", - pamh->env == NULL ? "":"-list" ); - return NULL; - } - - /* find the requested item */ - - item = _pam_search_env(pamh->env, name, strlen(name)); - if (item != -1) { - - D(("env-item: %s, found!", name)); - return (pamh->env->list[item] + 1 + strlen(name)); - - } else { - - D(("env-item: %s, not found", name)); - return NULL; - - } -} - -static char **_copy_env(pam_handle_t *pamh) -{ - char **dump; - int i = pamh->env->requested; /* reckon size of environment */ - char *const *env = pamh->env->list; - - D(("now get some memory for dump")); - - /* allocate some memory for this (plus the null tail-pointer) */ - dump = (char **) calloc(i, sizeof(char *)); - D(("dump = %p", dump)); - if (dump == NULL) { - return NULL; - } - - /* now run through entries and copy the variables over */ - dump[--i] = NULL; - while (i-- > 0) { - D(("env[%d]=`%s'", i,env[i])); - dump[i] = _pam_strdup(env[i]); - D(("->dump[%d]=`%s'", i,dump[i])); - if (dump[i] == NULL) { - /* out of memory */ - - while (dump[++i]) { - _pam_overwrite(dump[i]); - _pam_drop(dump[i]); - } - return NULL; - } - } - - env = NULL; /* forget now */ - - /* return transcribed environment */ - return dump; -} - -char **pam_getenvlist(pam_handle_t *pamh) -{ - int i; - - D(("called.")); - IF_NO_PAMH("pam_getenvlist", pamh, NULL); - - if (pamh->env == NULL || pamh->env->list == NULL) { - _pam_system_log(LOG_ERR, "pam_getenvlist: no env%s found", - pamh->env == NULL ? "":"-list" ); - return NULL; - } - - /* some quick checks */ - - if (pamh->env->requested > pamh->env->entries) { - _pam_system_log(LOG_ERR, "pam_getenvlist: environment corruption"); - _pam_dump_env(pamh); /* only active when debugging */ - return NULL; - } - - for (i=pamh->env->requested-1; i-- > 0; ) { - if (pamh->env->list[i] == NULL) { - _pam_system_log(LOG_ERR, "pam_getenvlist: environment broken"); - _pam_dump_env(pamh); /* only active when debugging */ - return NULL; /* somehow we've broken the environment!? */ - } - } - - /* Seems fine; copy environment */ - - _pam_dump_env(pamh); /* only active when debugging */ - - return _copy_env(pamh); -} diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c deleted file mode 100644 index 62b7446c..00000000 --- a/libpam/pam_handlers.c +++ /dev/null @@ -1,897 +0,0 @@ -/* pam_handlers.c -- pam config file parsing and module loading */ - -/* - * created by Marc Ewing. - * Currently maintained by Andrew G. Morgan <morgan@kernel.org> - * - * $Id$ - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#ifdef PAM_DYNAMIC -# ifdef PAM_SHL -# include <dl.h> -# else /* PAM_SHL */ -# include <dlfcn.h> -# endif /* PAM_SHL */ -#endif /* PAM_DYNAMIC */ - -#include "pam_private.h" - -/* If not required, define as nothing */ -#ifndef SHLIB_SYM_PREFIX -# define SHLIB_SYM_PREFIX "" -#endif - -#define BUF_SIZE 1024 -#define MODULE_CHUNK 4 -#define UNKNOWN_MODULE_PATH "<*unknown module path*>" - -static int _pam_assemble_line(FILE *f, char *buf, int buf_len); - -static void _pam_free_handlers_aux(struct handler **hp); - -static int _pam_add_handler(pam_handle_t *pamh - , int must_fail, int other, int type - , int *actions, const char *mod_path - , int argc, char **argv, int argvlen); - -/* Values for module type */ - -#define PAM_T_AUTH 1 -#define PAM_T_SESS 2 -#define PAM_T_ACCT 4 -#define PAM_T_PASS 8 - -static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f - , const char *known_service /* specific file */ -#ifdef PAM_READ_BOTH_CONFS - , int not_other -#endif /* PAM_READ_BOTH_CONFS */ - ) -{ - char buf[BUF_SIZE]; - int x; /* read a line from the FILE *f ? */ - /* - * read a line from the configuration (FILE *) f - */ - while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) { - char *tok, *nexttok=NULL; - const char *this_service; - const char *mod_path; - int module_type, actions[_PAM_RETURN_VALUES]; - int other; /* set if module is for PAM_DEFAULT_SERVICE */ - int res; /* module added successfully? */ - int must_fail=0; /* a badly formatted line must fail when used */ - int argc; - char **argv; - int argvlen; - - D(("_pam_init_handler: LINE: %s", buf)); - if (known_service != NULL) { - nexttok = buf; - /* No service field: all lines are for the known service. */ - this_service = known_service; - } else { - this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok); - } - -#ifdef PAM_READ_BOTH_CONFS - if (not_other) - other = 0; - else -#endif /* PAM_READ_BOTH_CONFS */ - other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE); - - /* accept "service name" or PAM_DEFAULT_SERVICE modules */ - if (!_pam_strCMP(this_service, pamh->service_name) || other) { - /* This is a service we are looking for */ - D(("_pam_init_handlers: Found PAM config entry for: %s" - , this_service)); - - tok = _pam_StrTok(NULL, " \n\t", &nexttok); - if (!_pam_strCMP("auth", tok)) { - module_type = PAM_T_AUTH; - } else if (!_pam_strCMP("session", tok)) { - module_type = PAM_T_SESS; - } else if (!_pam_strCMP("account", tok)) { - module_type = PAM_T_ACCT; - } else if (!_pam_strCMP("password", tok)) { - module_type = PAM_T_PASS; - } else { - /* Illegal module type */ - D(("_pam_init_handlers: bad module type: %s", tok)); - _pam_system_log(LOG_ERR, "(%s) illegal module type: %s", - this_service, tok); - module_type = PAM_T_AUTH; /* most sensitive */ - must_fail = 1; /* install as normal but fail when dispatched */ - } - D(("Using %s config entry: %s", must_fail?"BAD ":"", tok)); - - /* reset the actions to .._UNDEF's -- this is so that - we can work out which entries are not yet set (for default). */ - { - int i; - for (i=0; i<_PAM_RETURN_VALUES; - actions[i++] = _PAM_ACTION_UNDEF); - } - tok = _pam_StrTok(NULL, " \n\t", &nexttok); - if (!_pam_strCMP("required", tok)) { - D(("*PAM_F_REQUIRED*")); - actions[PAM_SUCCESS] = _PAM_ACTION_OK; - actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; - actions[PAM_IGNORE] = _PAM_ACTION_IGNORE; - _pam_set_default_control(actions, _PAM_ACTION_BAD); - } else if (!_pam_strCMP("requisite", tok)) { - D(("*PAM_F_REQUISITE*")); - actions[PAM_SUCCESS] = _PAM_ACTION_OK; - actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; - actions[PAM_IGNORE] = _PAM_ACTION_IGNORE; - _pam_set_default_control(actions, _PAM_ACTION_DIE); - } else if (!_pam_strCMP("optional", tok)) { - D(("*PAM_F_OPTIONAL*")); - actions[PAM_SUCCESS] = _PAM_ACTION_OK; - actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; - _pam_set_default_control(actions, _PAM_ACTION_IGNORE); - } else if (!_pam_strCMP("sufficient", tok)) { - D(("*PAM_F_SUFFICIENT*")); - actions[PAM_SUCCESS] = _PAM_ACTION_DONE; - actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE; - _pam_set_default_control(actions, _PAM_ACTION_IGNORE); - } else { - D(("will need to parse %s", tok)); - _pam_parse_control(actions, tok); - /* by default the default is to treat as failure */ - _pam_set_default_control(actions, _PAM_ACTION_BAD); - } - - tok = _pam_StrTok(NULL, " \n\t", &nexttok); - if (tok != NULL) { - mod_path = tok; - D(("mod_path = %s",mod_path)); - } else { - /* no module name given */ - D(("_pam_init_handlers: no module name supplied")); - _pam_system_log(LOG_ERR, - "(%s) no module name supplied", this_service); - mod_path = NULL; - must_fail = 1; - } - - /* nexttok points to remaining arguments... */ - - if (nexttok != NULL) { - D(("list: %s",nexttok)); - argvlen = _pam_mkargv(nexttok, &argv, &argc); - D(("argvlen = %d",argvlen)); - } else { /* there are no arguments so fix by hand */ - D(("_pam_init_handlers: empty argument list")); - argvlen = argc = 0; - argv = NULL; - } - -#ifdef DEBUG - { - int y; - - D(("CONF%s: %s%s %d %s %d" - , must_fail?"<*will fail*>":"" - , this_service, other ? "(backup)":"" - , module_type - , mod_path, argc)); - for (y = 0; y < argc; y++) { - D(("CONF: %s", argv[y])); - } - for (y = 0; y<_PAM_RETURN_VALUES; ++y) { - D(("RETURN %s(%d) -> %d %s", - _pam_token_returns[y], y, actions[y], - actions[y]>0 ? "jump": - _pam_token_actions[-actions[y]])); - } - } -#endif - - res = _pam_add_handler(pamh, must_fail, other - , module_type, actions, mod_path - , argc, argv, argvlen); - if (res != PAM_SUCCESS) { - _pam_system_log(LOG_ERR, "error loading %s", mod_path); - D(("failed to load module - aborting")); - return PAM_ABORT; - } - } - } - - return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS ); -} - -/* Parse config file, allocate handler structures, dlopen() */ -int _pam_init_handlers(pam_handle_t *pamh) -{ - FILE *f; - int retval; - - D(("_pam_init_handlers called")); - IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR); - - /* Return immediately if everything is already loaded */ - if (pamh->handlers.handlers_loaded) { - return PAM_SUCCESS; - } - - D(("_pam_init_handlers: initializing")); - - /* First clean the service structure */ - - _pam_free_handlers(pamh); - if (! pamh->handlers.module) { - if ((pamh->handlers.module = - malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) { - _pam_system_log(LOG_CRIT, - "_pam_init_handlers: no memory loading module"); - return PAM_BUF_ERR; - } - pamh->handlers.modules_allocated = MODULE_CHUNK; - pamh->handlers.modules_used = 0; - } - - if (pamh->service_name == NULL) { - return PAM_BAD_ITEM; /* XXX - better error? */ - } - -#ifdef PAM_LOCKING - /* Is the PAM subsystem locked? */ - { - int fd_tmp; - - if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) { - _pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile (" - PAM_LOCK_FILE ") exists - aborting"); - (void) close(fd_tmp); - /* - * to avoid swamping the system with requests - */ - _pam_start_timer(pamh); - pam_fail_delay(pamh, 5000000); - _pam_await_timer(pamh, PAM_ABORT); - - return PAM_ABORT; - } - } -#endif /* PAM_LOCKING */ - - /* - * Now parse the config file(s) and add handlers - */ - { - struct stat test_d; - - /* Is there a PAM_CONFIG_D directory? */ - if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) { - char *filename; - int read_something=0; - - D(("searching " PAM_CONFIG_D " for config files")); - filename = malloc(sizeof(PAM_CONFIG_DF) - +strlen(pamh->service_name)); - if (filename == NULL) { - _pam_system_log(LOG_ERR, - "_pam_init_handlers: no memory; service %s", - pamh->service_name); - return PAM_BUF_ERR; - } - sprintf(filename, PAM_CONFIG_DF, pamh->service_name); - D(("opening %s", filename)); - f = fopen(filename, "r"); - if (f != NULL) { - /* would test magic here? */ - retval = _pam_parse_conf_file(pamh, f, pamh->service_name -#ifdef PAM_READ_BOTH_CONFS - , 0 -#endif /* PAM_READ_BOTH_CONFS */ - ); - fclose(f); - if (retval != PAM_SUCCESS) { - _pam_system_log(LOG_ERR, - "_pam_init_handlers: error reading %s", - filename); - _pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]", - pam_strerror(pamh, retval)); - } else { - read_something = 1; - } - } else { - D(("unable to open %s", filename)); -#ifdef PAM_READ_BOTH_CONFS - D(("checking %s", PAM_CONFIG)); - - if ((f = fopen(PAM_CONFIG,"r")) != NULL) { - retval = _pam_parse_conf_file(pamh, f, NULL, 1); - fclose(f); - } else -#endif /* PAM_READ_BOTH_CONFS */ - retval = PAM_SUCCESS; - /* - * XXX - should we log an error? Some people want to always - * use "other" - */ - } - _pam_drop(filename); - - if (retval == PAM_SUCCESS) { - /* now parse the PAM_DEFAULT_SERVICE_FILE */ - - D(("opening %s", PAM_DEFAULT_SERVICE_FILE)); - f = fopen(PAM_DEFAULT_SERVICE_FILE, "r"); - if (f != NULL) { - /* would test magic here? */ - retval = _pam_parse_conf_file(pamh, f - , PAM_DEFAULT_SERVICE -#ifdef PAM_READ_BOTH_CONFS - , 0 -#endif /* PAM_READ_BOTH_CONFS */ - ); - fclose(f); - if (retval != PAM_SUCCESS) { - _pam_system_log(LOG_ERR, - "_pam_init_handlers: error reading %s", - PAM_DEFAULT_SERVICE_FILE); - _pam_system_log(LOG_ERR, - "_pam_init_handlers: [%s]", - pam_strerror(pamh, retval)); - } else { - read_something = 1; - } - } else { - D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE)); - _pam_system_log(LOG_ERR, - "_pam_init_handlers: no default config %s", - PAM_DEFAULT_SERVICE_FILE); - } - if (!read_something) { /* nothing read successfully */ - retval = PAM_ABORT; - } - } - } else { - if ((f = fopen(PAM_CONFIG, "r")) == NULL) { - _pam_system_log(LOG_ERR, "_pam_init_handlers: could not open " - PAM_CONFIG ); - return PAM_ABORT; - } - - retval = _pam_parse_conf_file(pamh, f, NULL -#ifdef PAM_READ_BOTH_CONFS - , 0 -#endif /* PAM_READ_BOTH_CONFS */ - ); - - D(("closing configuration file")); - fclose(f); - } - } - - if (retval != PAM_SUCCESS) { - /* Read error */ - _pam_system_log(LOG_ERR, "error reading PAM configuration file"); - return PAM_ABORT; - } - - pamh->handlers.handlers_loaded = 1; - - D(("_pam_init_handlers exiting")); - return PAM_SUCCESS; -} - -/* - * This is where we read a line of the PAM config file. The line may be - * preceeded by lines of comments and also extended with "\\\n" - */ - -static int _pam_assemble_line(FILE *f, char *buffer, int buf_len) -{ - char *p = buffer; - char *s, *os; - int used = 0; - - /* loop broken with a 'break' when a non-'\\n' ended line is read */ - - D(("called.")); - for (;;) { - if (used >= buf_len) { - /* Overflow */ - D(("_pam_assemble_line: overflow")); - return -1; - } - if (fgets(p, buf_len - used, f) == NULL) { - if (used) { - /* Incomplete read */ - return -1; - } else { - /* EOF */ - return 0; - } - } - - /* skip leading spaces --- line may be blank */ - - s = p + strspn(p, " \n\t"); - if (*s && (*s != '#')) { - os = s; - - /* - * we are only interested in characters before the first '#' - * character - */ - - while (*s && *s != '#') - ++s; - if (*s == '#') { - *s = '\0'; - used += strlen(os); - break; /* the line has been read */ - } - - s = os; - - /* - * Check for backslash by scanning back from the end of - * the entered line, the '\n' has been included since - * normally a line is terminated with this - * character. fgets() should only return one though! - */ - - s += strlen(s); - while (s > os && ((*--s == ' ') || (*s == '\t') - || (*s == '\n'))); - - /* check if it ends with a backslash */ - if (*s == '\\') { - *s++ = ' '; /* replace backslash with ' ' */ - *s = '\0'; /* truncate the line here */ - used += strlen(os); - p = s; /* there is more ... */ - } else { - /* End of the line! */ - used += strlen(os); - break; /* this is the complete line */ - } - - } else { - /* Nothing in this line */ - /* Don't move p */ - } - } - - return used; -} - -typedef int (*servicefn)(pam_handle_t *, int, int, char **); - -int _pam_add_handler(pam_handle_t *pamh - , int must_fail, int other, int type - , int *actions, const char *mod_path - , int argc, char **argv, int argvlen) -{ - struct loaded_module *mod; - int x = 0; - struct handler **handler_p; - struct handler **handler_p2; - struct handlers *the_handlers; - const char *sym, *sym2; -#ifdef PAM_SHL - const char *_sym, *_sym2; -#endif - char *mod_full_path=NULL; - servicefn func, func2; - int success; - - D(("called.")); - IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR); - - /* if NULL set to something that can be searched for */ - switch (mod_path != NULL) { - default: - if (mod_path[0] == '/') { - break; - } - mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path)); - if (mod_full_path) { - sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path); - mod_path = mod_full_path; - break; - } - _pam_system_log(LOG_CRIT, "cannot malloc full mod path"); - case 0: - mod_path = UNKNOWN_MODULE_PATH; - } - - D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path)); - mod = pamh->handlers.module; - - /* First, ensure the module is loaded */ - while (x < pamh->handlers.modules_used) { - if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */ - break; - } - x++; - } - if (x == pamh->handlers.modules_used) { - /* Not found */ - if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) { - /* will need more memory */ - void *tmp = realloc(pamh->handlers.module, - (pamh->handlers.modules_allocated+MODULE_CHUNK) - *sizeof(struct loaded_module)); - if (tmp == NULL) { - D(("cannot enlarge module pointer memory")); - _pam_system_log(LOG_ERR, - "realloc returned NULL in _pam_add_handler"); - _pam_drop(mod_full_path); - return PAM_ABORT; - } - pamh->handlers.module = tmp; - pamh->handlers.modules_allocated += MODULE_CHUNK; - } - mod = &(pamh->handlers.module[x]); - /* Be pessimistic... */ - success = PAM_ABORT; - -#ifdef PAM_DYNAMIC - D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle)); - mod->dl_handle = -# ifdef PAM_SHL - shl_load(mod_path, BIND_IMMEDIATE, 0L); -# else /* PAM_SHL */ - dlopen(mod_path, RTLD_NOW); -# endif /* PAM_SHL */ - D(("_pam_add_handler: dlopen'ed")); - if (mod->dl_handle == NULL) { - D(("_pam_add_handler: dlopen(%s) failed", mod_path)); - _pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path); -# ifndef PAM_SHL - _pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror()); -# endif /* PAM_SHL */ - /* Don't abort yet; static code may be able to find function. - * But defaults to abort if nothing found below... */ - } else { - D(("module added successfully")); - success = PAM_SUCCESS; - mod->type = PAM_MT_DYNAMIC_MOD; - pamh->handlers.modules_used++; - } -#endif -#ifdef PAM_STATIC - /* Only load static function if function was not found dynamically. - * This code should work even if no dynamic loading is available. */ - if (success != PAM_SUCCESS) { - D(("_pam_add_handler: open static handler %s", mod_path)); - mod->dl_handle = _pam_open_static_handler(mod_path); - if (mod->dl_handle == NULL) { - D(("_pam_add_handler: unable to find static handler %s", - mod_path)); - _pam_system_log(LOG_ERR, - "unable to open static handler %s", mod_path); - /* Didn't find module in dynamic or static..will mark bad */ - } else { - D(("static module added successfully")); - success = PAM_SUCCESS; - mod->type = PAM_MT_STATIC_MOD; - pamh->handlers.modules_used++; - } - } -#endif - - if (success != PAM_SUCCESS) { /* add a malformed module */ - mod->dl_handle = NULL; - mod->type = PAM_MT_FAULTY_MOD; - pamh->handlers.modules_used++; - _pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path); - success = PAM_SUCCESS; /* We have successfully added a module */ - } - - /* indicate its name - later we will search for it by this */ - if ((mod->name = _pam_strdup(mod_path)) == NULL) { - D(("_pam_handler: couldn't get memory for mod_path")); - _pam_system_log(LOG_ERR, "no memory for module path", mod_path); - success = PAM_ABORT; - } - - } else { /* x != pamh->handlers.modules_used */ - mod += x; /* the located module */ - success = PAM_SUCCESS; - } - - _pam_drop(mod_full_path); - mod_path = NULL; /* no longer needed or trusted */ - - /* Now return error if necessary after trying all possible ways... */ - if (success != PAM_SUCCESS) - return(success); - - /* - * At this point 'mod' points to the stored/loaded module. If its - * dl_handle is unknown, then we must be able to indicate dispatch - * failure with 'must_fail' - */ - - /* Now define the handler(s) based on mod->dlhandle and type */ - - /* decide which list of handlers to use */ - the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf; - - handler_p = handler_p2 = NULL; - func = func2 = NULL; -#ifdef PAM_SHL - _sym2 = -#endif /* PAM_SHL */ - sym2 = NULL; - - /* point handler_p's at the root addresses of the function stacks */ - switch (type) { - case PAM_T_AUTH: - handler_p = &the_handlers->authenticate; - sym = SHLIB_SYM_PREFIX "pam_sm_authenticate"; - handler_p2 = &the_handlers->setcred; - sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred"; -#ifdef PAM_SHL - _sym = "_pam_sm_authenticate"; - _sym2 = "_pam_sm_setcred"; -#endif - break; - case PAM_T_SESS: - handler_p = &the_handlers->open_session; - sym = SHLIB_SYM_PREFIX "pam_sm_open_session"; - handler_p2 = &the_handlers->close_session; - sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session"; -#ifdef PAM_SHL - _sym = "_pam_sm_open_session"; - _sym2 = "_pam_sm_close_session"; -#endif - break; - case PAM_T_ACCT: - handler_p = &the_handlers->acct_mgmt; - sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt"; -#ifdef PAM_SHL - _sym = "_pam_sm_acct_mgmt"; -#endif - break; - case PAM_T_PASS: - handler_p = &the_handlers->chauthtok; - sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok"; -#ifdef PAM_SHL - _sym = "_pam_sm_chauthtok"; -#endif - break; - default: - /* Illegal module type */ - D(("_pam_add_handler: illegal module type %d", type)); - return PAM_ABORT; - } - - /* are the modules reliable? */ - if ( -#ifdef PAM_DYNAMIC - mod->type != PAM_MT_DYNAMIC_MOD - && -#endif /* PAM_DYNAMIC */ -#ifdef PAM_STATIC - mod->type != PAM_MT_STATIC_MOD - && -#endif /* PAM_STATIC */ - mod->type != PAM_MT_FAULTY_MOD - ) { - D(("_pam_add_handlers: illegal module library type; %d", mod->type)); - _pam_system_log(LOG_ERR, - "internal error: module library type not known: %s;%d", - sym, mod->type); - return PAM_ABORT; - } - - /* now identify this module's functions - for non-faulty modules */ - -#ifdef PAM_DYNAMIC - if ((mod->type == PAM_MT_DYNAMIC_MOD) && -# ifdef PAM_SHL - (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) && - shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func)) -# else /* PAM_SHL */ - (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL -# endif /* PAM_SHL */ - ) { - _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym); - } -#endif -#ifdef PAM_STATIC - if ((mod->type == PAM_MT_STATIC_MOD) && - (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) { - _pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym); - } -#endif - if (sym2) { -#ifdef PAM_DYNAMIC - if ((mod->type == PAM_MT_DYNAMIC_MOD) && -# ifdef PAM_SHL - (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&& - shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2)) -# else /* PAM_SHL */ - (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL -# endif /* PAM_SHL */ - ) { - _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2); - } -#endif -#ifdef PAM_STATIC - if ((mod->type == PAM_MT_STATIC_MOD) && - (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2)) - == NULL) { - _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2); - } -#endif - } - - /* here func (and perhaps func2) point to the appropriate functions */ - - /* add new handler to end of existing list */ - while (*handler_p != NULL) { - handler_p = &((*handler_p)->next); - } - - if ((*handler_p = malloc(sizeof(struct handler))) == NULL) { - _pam_system_log(LOG_CRIT, "cannot malloc struct handler #1"); - return (PAM_ABORT); - } - - (*handler_p)->must_fail = must_fail; /* failure forced? */ - (*handler_p)->func = func; - memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions)); - (*handler_p)->cached_retval = _PAM_INVALID_RETVAL; - (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval); - (*handler_p)->argc = argc; - (*handler_p)->argv = argv; /* not a copy */ - (*handler_p)->next = NULL; - - /* some of the modules have a second calling function */ - if (handler_p2) { - /* add new handler to end of existing list */ - while (*handler_p2) { - handler_p2 = &((*handler_p2)->next); - } - - if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) { - _pam_system_log(LOG_CRIT, "cannot malloc struct handler #2"); - return (PAM_ABORT); - } - - (*handler_p2)->must_fail = must_fail; /* failure forced? */ - (*handler_p2)->func = func2; - memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions)); - (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */ - /* Note, this next entry points to the handler_p value! */ - (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval); - (*handler_p2)->argc = argc; - if (argv) { - if (((*handler_p2)->argv = malloc(argvlen)) == NULL) { - _pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2"); - return (PAM_ABORT); - } - memcpy((*handler_p2)->argv, argv, argvlen); - } else { - (*handler_p2)->argv = NULL; /* no arguments */ - } - (*handler_p2)->next = NULL; - } - - D(("_pam_add_handler: returning successfully")); - - return PAM_SUCCESS; -} - -/* Free various allocated structures and dlclose() the libs */ -int _pam_free_handlers(pam_handle_t *pamh) -{ - struct loaded_module *mod; - - D(("called.")); - IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR); - - mod = pamh->handlers.module; - - /* Close all loaded modules */ - - while (pamh->handlers.modules_used) { - D(("_pam_free_handlers: dlclose(%s)", mod->name)); - free(mod->name); -#ifdef PAM_DYNAMIC - if (mod->type == PAM_MT_DYNAMIC_MOD) { -# ifdef PAM_SHL - shl_unload(mod->dl_handle); -# else - dlclose(mod->dl_handle); -# endif - } -#endif - mod++; - pamh->handlers.modules_used--; - } - - /* Free all the handlers */ - - _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate)); - _pam_free_handlers_aux(&(pamh->handlers.conf.setcred)); - _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt)); - _pam_free_handlers_aux(&(pamh->handlers.conf.open_session)); - _pam_free_handlers_aux(&(pamh->handlers.conf.close_session)); - _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok)); - - _pam_free_handlers_aux(&(pamh->handlers.other.authenticate)); - _pam_free_handlers_aux(&(pamh->handlers.other.setcred)); - _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt)); - _pam_free_handlers_aux(&(pamh->handlers.other.open_session)); - _pam_free_handlers_aux(&(pamh->handlers.other.close_session)); - _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok)); - - /* no more loaded modules */ - - _pam_drop(pamh->handlers.module); - - /* Indicate that handlers are not initialized for this pamh */ - - pamh->handlers.handlers_loaded = 0; - - return PAM_SUCCESS; -} - -void _pam_start_handlers(pam_handle_t *pamh) -{ - D(("called.")); - /* NB. There is no check for a NULL pamh here, since no return - * value to communicate the fact! */ - - /* Indicate that handlers are not initialized for this pamh */ - pamh->handlers.handlers_loaded = 0; - - pamh->handlers.modules_allocated = 0; - pamh->handlers.modules_used = 0; - pamh->handlers.module = NULL; - - /* initialize the .conf and .other entries */ - - pamh->handlers.conf.authenticate = NULL; - pamh->handlers.conf.setcred = NULL; - pamh->handlers.conf.acct_mgmt = NULL; - pamh->handlers.conf.open_session = NULL; - pamh->handlers.conf.close_session = NULL; - pamh->handlers.conf.chauthtok = NULL; - - pamh->handlers.other.authenticate = NULL; - pamh->handlers.other.setcred = NULL; - pamh->handlers.other.acct_mgmt = NULL; - pamh->handlers.other.open_session = NULL; - pamh->handlers.other.close_session = NULL; - pamh->handlers.other.chauthtok = NULL; -} - -void _pam_free_handlers_aux(struct handler **hp) -{ - struct handler *h = *hp; - struct handler *last; - - D(("called.")); - while (h) { - last = h; - _pam_drop(h->argv); /* This is all alocated in a single chunk */ - h = h->next; - memset(last, 0, sizeof(*last)); - free(last); - } - - *hp = NULL; -} diff --git a/libpam/pam_item.c b/libpam/pam_item.c deleted file mode 100644 index 2b4c32ef..00000000 --- a/libpam/pam_item.c +++ /dev/null @@ -1,333 +0,0 @@ -/* pam_item.c */ - -/* - * $Id$ - */ - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> - -#include "pam_private.h" - -#define RESET(X, Y) \ -{ \ - char *_TMP_ = (X); \ - if (_TMP_ != (Y)) { \ - (X) = (Y) ? _pam_strdup(Y) : NULL; \ - if (_TMP_) \ - free(_TMP_); \ - } \ -} - -/* handy version id */ - -unsigned int __libpam_version = LIBPAM_VERSION; - -/* functions */ - -int pam_set_item (pam_handle_t *pamh, int item_type, const void *item) -{ - int retval; - - D(("called")); - - IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR); - - retval = PAM_SUCCESS; - - switch (item_type) { - - case PAM_SERVICE: - /* Setting handlers_loaded to 0 will cause the handlers - * to be reloaded on the next call to a service module. - */ - pamh->handlers.handlers_loaded = 0; - RESET(pamh->service_name, item); - { - char *tmp; - for (tmp=pamh->service_name; *tmp; ++tmp) - *tmp = tolower(*tmp); /* require lower case */ - } - break; - - case PAM_USER: - RESET(pamh->user, item); - break; - - case PAM_USER_PROMPT: - RESET(pamh->prompt, item); - break; - - case PAM_TTY: - D(("setting tty to %s", item)); - RESET(pamh->tty, item); - break; - - case PAM_RUSER: - RESET(pamh->ruser, item); - break; - - case PAM_RHOST: - RESET(pamh->rhost, item); - break; - - case PAM_AUTHTOK: - /* - * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from - * modules. - */ - if (__PAM_FROM_MODULE(pamh)) { - char *_TMP_ = pamh->authtok; - if (_TMP_ == item) /* not changed so leave alone */ - break; - pamh->authtok = (item) ? _pam_strdup(item) : NULL; - if (_TMP_) { - _pam_overwrite(_TMP_); - free(_TMP_); - } - } else { - retval = PAM_BAD_ITEM; - } - - break; - - case PAM_OLDAUTHTOK: - /* - * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from - * modules. - */ - if (__PAM_FROM_MODULE(pamh)) { - char *_TMP_ = pamh->oldauthtok; - if (_TMP_ == item) /* not changed so leave alone */ - break; - pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL; - if (_TMP_) { - _pam_overwrite(_TMP_); - free(_TMP_); - } - } else { - retval = PAM_BAD_ITEM; - } - - break; - - case PAM_CONV: /* want to change the conversation function */ - if (item == NULL) { - _pam_system_log(LOG_ERR, - "pam_set_item: attempt to set conv() to NULL"); - retval = PAM_PERM_DENIED; - } else { - struct pam_conv *tconv; - - if ((tconv= - (struct pam_conv *) malloc(sizeof(struct pam_conv)) - ) == NULL) { - _pam_system_log(LOG_CRIT, - "pam_set_item: malloc failed for pam_conv"); - retval = PAM_BUF_ERR; - } else { - memcpy(tconv, item, sizeof(struct pam_conv)); - _pam_drop(pamh->pam_conversation); - pamh->pam_conversation = tconv; - } - } - break; - - case PAM_FAIL_DELAY: - pamh->fail_delay.delay_fn_ptr = item; - break; - - default: - retval = PAM_BAD_ITEM; - } - - return retval; -} - -int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item) -{ - int retval = PAM_SUCCESS; - - D(("called.")); - IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR); - - if (item == NULL) { - _pam_system_log(LOG_ERR, - "pam_get_item: nowhere to place requested item"); - return PAM_PERM_DENIED; - } - - switch (item_type) { - case PAM_SERVICE: - *item = pamh->service_name; - break; - - case PAM_USER: - D(("returning user=%s", pamh->user)); - *item = pamh->user; - break; - - case PAM_USER_PROMPT: - D(("returning userprompt=%s", pamh->user)); - *item = pamh->prompt; - break; - - case PAM_TTY: - D(("returning tty=%s", pamh->tty)); - *item = pamh->tty; - break; - - case PAM_RUSER: - *item = pamh->ruser; - break; - - case PAM_RHOST: - *item = pamh->rhost; - break; - - case PAM_AUTHTOK: - /* - * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from - * modules. - */ - if (__PAM_FROM_MODULE(pamh)) { - *item = pamh->authtok; - } else { - retval = PAM_BAD_ITEM; - } - break; - - case PAM_OLDAUTHTOK: - /* - * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from - * modules. - */ - if (__PAM_FROM_MODULE(pamh)) { - *item = pamh->oldauthtok; - } else { - retval = PAM_BAD_ITEM; - } - break; - - case PAM_CONV: - *item = pamh->pam_conversation; - break; - - case PAM_FAIL_DELAY: - *item = pamh->fail_delay.delay_fn_ptr; - break; - - default: - retval = PAM_BAD_ITEM; - } - - return retval; -} - -/* - * This function is the 'preferred method to obtain the username'. - */ - -int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) -{ - const char *use_prompt; - int retval; - struct pam_message msg,*pmsg; - struct pam_response *resp; - - D(("called.")); - IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR); - - if (pamh->pam_conversation == NULL) { - _pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh"); - return PAM_SERVICE_ERR; - } - - if (user == NULL) { /* ensure the the module has suplied a destination */ - _pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username"); - return PAM_PERM_DENIED; - } else - *user = NULL; - - if (pamh->user) { /* have one so return it */ - *user = pamh->user; - return PAM_SUCCESS; - } - - /* will need a prompt */ - use_prompt = prompt; - if (use_prompt == NULL) { - use_prompt = pamh->prompt; - if (use_prompt == NULL) { - use_prompt = PAM_DEFAULT_PROMPT; - } - } - - /* If we are resuming an old conversation, we verify that the prompt - is the same. Anything else is an error. */ - if (pamh->former.want_user) { - /* must have a prompt to resume with */ - if (! pamh->former.prompt) { - _pam_system_log(LOG_ERR, - "pam_get_user: failed to resume with prompt" - ); - return PAM_ABORT; - } - - /* must be the same prompt as last time */ - if (strcmp(pamh->former.prompt, use_prompt)) { - _pam_system_log(LOG_ERR, - "pam_get_user: resumed with different prompt"); - return PAM_ABORT; - } - - /* ok, we can resume where we left off last time */ - pamh->former.want_user = PAM_FALSE; - _pam_overwrite(pamh->former.prompt); - _pam_drop(pamh->former.prompt); - } - - /* converse with application -- prompt user for a username */ - pmsg = &msg; - msg.msg_style = PAM_PROMPT_ECHO_ON; - msg.msg = use_prompt; - resp = NULL; - - retval = pamh->pam_conversation-> - conv(1, (const struct pam_message **) &pmsg, &resp, - pamh->pam_conversation->appdata_ptr); - - if (retval == PAM_CONV_AGAIN) { - /* conversation function is waiting for an event - save state */ - D(("conversation function is not ready yet")); - pamh->former.want_user = PAM_TRUE; - pamh->former.prompt = _pam_strdup(use_prompt); - } else if (resp == NULL) { - /* - * conversation should have given a response - */ - D(("pam_get_user: no response provided")); - retval = PAM_CONV_ERR; - } else if (retval == PAM_SUCCESS) { /* copy the username */ - /* - * now we set the PAM_USER item -- this was missing from pre.53 - * releases. However, reading the Sun manual, it is part of - * the standard API. - */ - RESET(pamh->user, resp->resp); - *user = pamh->user; - } - - if (resp) { - /* - * note 'resp' is allocated by the application and is - * correctly free()'d here - */ - _pam_drop_reply(resp, 1); - } - - D(("completed")); - return retval; /* pass on any error from conversation */ -} diff --git a/libpam/pam_log.c b/libpam/pam_log.c deleted file mode 100644 index af6f2504..00000000 --- a/libpam/pam_log.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * pam_log.c -- PAM system logging - * - * $Id$ - * - */ - -#include "pam_private.h" - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> - -#ifdef __hpux -# include <stdio.h> -# include <syslog.h> -# ifdef __STDC__ -# ifndef __P -# define __P(p) p -# endif /* __P */ -# include <stdarg.h> -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap, f) -# define VA_END va_end(ap) -# else /* __STDC__ */ -# ifndef __P -# define __P(p) () -# endif /* __P */ -# include <varargs.h> -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap) -# define VA_END va_end(ap) -# endif /* __STDC__ */ -/************************************************************** - * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. - * Sigh. This sort of thing is always nasty do deal with. Note that - * the version here does not include floating point... - * - * snprintf() is used instead of sprintf() as it does limit checks - * for string length. This covers a nasty loophole. - * - * The other functions are there to prevent NULL pointers from - * causing nast effects. - **************************************************************/ - -static void dopr(); -static char *end; -# ifndef _SCO_DS -/* VARARGS3 */ -int -# ifdef __STDC__ -snprintf(char *str, size_t count, const char *fmt, ...) -# else /* __STDC__ */ -snprintf(str, count, fmt, va_alist) - char *str; - size_t count; - const char *fmt; - va_dcl -# endif /* __STDC__ */ -{ - int len; - VA_LOCAL_DECL - - VA_START(fmt); - len = vsnprintf(str, count, fmt, ap); - VA_END; - return len; -} -# endif /* _SCO_DS */ - -int -# ifdef __STDC__ -vsnprintf(char *str, size_t count, const char *fmt, va_list args) -# else /* __STDC__ */ -vsnprintf(str, count, fmt, args) - char *str; - int count; - char *fmt; - va_list args; -# endif /* __STDC__ */ -{ - str[0] = 0; - end = str + count - 1; - dopr( str, fmt, args ); - if (count > 0) - end[0] = 0; - return strlen(str); -} - -/* - * dopr(): poor man's version of doprintf - */ - -static void fmtstr __P((char *value, int ljust, int len, int zpad, - int maxwidth)); -static void fmtnum __P((long value, int base, int dosign, int ljust, int len, - int zpad)); -static void dostr __P(( char * , int )); -static char *output; -static void dopr_outch __P(( int c )); - -static void -# ifdef __STDC__ -dopr(char * buffer, const char * format, va_list args ) -# else /* __STDC__ */ -dopr( buffer, format, args ) - char *buffer; - char *format; - va_list args; -# endif /* __STDC__ */ -{ - int ch; - long value; - int longflag = 0; - int pointflag = 0; - int maxwidth = 0; - char *strvalue; - int ljust; - int len; - int zpad; - - output = buffer; - while( (ch = *format++) ){ - switch( ch ){ - case '%': - ljust = len = zpad = maxwidth = 0; - longflag = pointflag = 0; - nextch: - ch = *format++; - switch( ch ){ - case 0: - dostr( "**end of format**" , 0); - return; - case '-': ljust = 1; goto nextch; - case '0': /* set zero padding if len not set */ - if(len==0 && !pointflag) zpad = '0'; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - if (pointflag) - maxwidth = maxwidth*10 + ch - '0'; - else - len = len*10 + ch - '0'; - goto nextch; - case '*': - if (pointflag) - maxwidth = va_arg( args, int ); - else - len = va_arg( args, int ); - goto nextch; - case '.': pointflag = 1; goto nextch; - case 'l': longflag = 1; goto nextch; - case 'u': case 'U': - /*fmtnum(value,base,dosign,ljust,len,zpad) */ - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 10,0, ljust, len, zpad ); break; - case 'o': case 'O': - /*fmtnum(value,base,dosign,ljust,len,zpad) */ - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 8,0, ljust, len, zpad ); break; - case 'd': case 'D': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 10,1, ljust, len, zpad ); break; - case 'x': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value, 16,0, ljust, len, zpad ); break; - case 'X': - if( longflag ){ - value = va_arg( args, long ); - } else { - value = va_arg( args, int ); - } - fmtnum( value,-16,0, ljust, len, zpad ); break; - case 's': - strvalue = va_arg( args, char *); - if (maxwidth > 0 || !pointflag) { - if (pointflag && len > maxwidth) - len = maxwidth; /* Adjust padding */ - fmtstr( strvalue,ljust,len,zpad, maxwidth); - } - break; - case 'c': - ch = va_arg( args, int ); - dopr_outch( ch ); break; - case '%': dopr_outch( ch ); continue; - default: - dostr( "???????" , 0); - } - break; - default: - dopr_outch( ch ); - break; - } - } - *output = 0; -} - -static void -fmtstr( value, ljust, len, zpad, maxwidth ) - char *value; - int ljust, len, zpad, maxwidth; -{ - int padlen, strlen; /* amount to pad */ - - if( value == 0 ){ - value = "<NULL>"; - } - for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */ - if (strlen > maxwidth && maxwidth) - strlen = maxwidth; - padlen = len - strlen; - if( padlen < 0 ) padlen = 0; - if( ljust ) padlen = -padlen; - while( padlen > 0 ) { - dopr_outch( ' ' ); - --padlen; - } - dostr( value, maxwidth ); - while( padlen < 0 ) { - dopr_outch( ' ' ); - ++padlen; - } -} - -static void -fmtnum( value, base, dosign, ljust, len, zpad ) - long value; - int base, dosign, ljust, len, zpad; -{ - int signvalue = 0; - unsigned long uvalue; - char convert[20]; - int place = 0; - int padlen = 0; /* amount to pad */ - int caps = 0; - - /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", - value, base, dosign, ljust, len, zpad )); */ - uvalue = value; - if( dosign ){ - if( value < 0 ) { - signvalue = '-'; - uvalue = -value; - } - } - if( base < 0 ){ - caps = 1; - base = -base; - } - do{ - convert[place++] = - (caps? "0123456789ABCDEF":"0123456789abcdef") - [uvalue % (unsigned)base ]; - uvalue = (uvalue / (unsigned)base ); - }while(uvalue); - convert[place] = 0; - padlen = len - place; - if( padlen < 0 ) padlen = 0; - if( ljust ) padlen = -padlen; - /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", - convert,place,signvalue,padlen)); */ - if( zpad && padlen > 0 ){ - if( signvalue ){ - dopr_outch( signvalue ); - --padlen; - signvalue = 0; - } - while( padlen > 0 ){ - dopr_outch( zpad ); - --padlen; - } - } - while( padlen > 0 ) { - dopr_outch( ' ' ); - --padlen; - } - if( signvalue ) dopr_outch( signvalue ); - while( place > 0 ) dopr_outch( convert[--place] ); - while( padlen < 0 ){ - dopr_outch( ' ' ); - ++padlen; - } -} - -static void -dostr( str , cut) - char *str; - int cut; -{ - if (cut) { - while(*str && cut-- > 0) dopr_outch(*str++); - } else { - while(*str) dopr_outch(*str++); - } -} - -static void -dopr_outch( c ) - int c; -{ - if( end == 0 || output < end ) - *output++ = c; -} - -int -# ifdef __STDC__ -vsyslog(int priority, const char *fmt, ...) -# else /* __STDC__ */ -vsyslog(priority, fmt, va_alist) - int priority; - const char *fmt; - va_dcl -# endif /* __STDC__ */ -{ - VA_LOCAL_DECL - char logbuf[BUFSIZ]; - - VA_START(fmt); - - vsnprintf(logbuf, BUFSIZ, fmt, ap); - syslog(priority, "%s", logbuf); - - VA_END; -} -#endif /* __hpux */ - -/* internal logging function */ - -void _pam_system_log(int priority, const char *format, ... ) -{ - va_list args; - char *eformat; - - D(("pam_system_log called")); - - if (format == NULL) { - D(("NULL format to _pam_system_log() call")); - return; - } - - va_start(args, format); - - eformat = malloc(sizeof(_PAM_SYSTEM_LOG_PREFIX)+strlen(format)); - if (eformat != NULL) { - strcpy(eformat, _PAM_SYSTEM_LOG_PREFIX); - strcpy(eformat + sizeof(_PAM_SYSTEM_LOG_PREFIX) - 1, format); - vsyslog(priority, eformat, args); - _pam_overwrite(eformat); - _pam_drop(eformat); - } else { - vsyslog(priority, format, args); - } - - va_end(args); - - D(("done.")); -} - diff --git a/libpam/pam_malloc.c b/libpam/pam_malloc.c deleted file mode 100644 index 75a1045d..00000000 --- a/libpam/pam_malloc.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * $Id$ - */ - -/* - * This pair of files helps to locate memory leaks. It is a wrapper for - * the malloc family of calls. (Actutally, it currently only deals - * with calloc, malloc, realloc, free, strdup and exit) - * - * To use these functions the header "pam_malloc.h" must be included - * in all parts of the code (that use the malloc functions) and this - * file must be linked with the result. The pam_malloc_flags can be - * set from another function and determine the level of logging. - * - * The output is via the macros defined in _pam_macros.h - * - * It is a debugging tool and should be turned off in released code. - * - * This suite was written by Andrew Morgan <morgan@kernel.org> for - * Linux-PAM. - */ - -#ifndef DEBUG -#define DEBUG -#endif -#include "pam_private.h" - -#include <security/pam_malloc.h> -#include <security/_pam_macros.h> - -/* this must be done to stop infinite recursion! */ -#undef malloc -#undef calloc -#undef free -#undef realloc -#undef exit -#undef strdup - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -/* - * default debugging level - */ - -int pam_malloc_flags = PAM_MALLOC_ALL; -int pam_malloc_delay_length = 4; - -#define on(x) ((pam_malloc_flags&(x))==(x)) - -/* - * the implementation - */ - -static const char *last_fn=NULL; -static const char *last_file=NULL; -static const char *last_call=NULL; -static int last_line = 1; - -#define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; } - -static void set_last_(const char *x, const char *f - , const char *fn, const int l) -{ - last_fn = x ? x : "error-in-pam_malloc.."; - last_file = f ? f : "*bad-file*"; - last_call = fn ? fn: "*bad-fn*"; - last_line = l; -} - -static void _pam_output_xdebug_info(void) -{ - FILE *logfile; - int must_close = 1, fd; - -#ifdef O_NOFOLLOW - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) { -#else - if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) { -#endif - if (!(logfile = fdopen(fd,"a"))) { - logfile = stderr; - must_close = 0; - close(fd); - } - } else { - logfile = stderr; - must_close = 0; - } - fprintf(logfile, "[%s:%s(%d)->%s()] ", - last_file, last_call, last_line, last_fn); - fflush(logfile); - if (must_close) - fclose(logfile); -} - -static void hinder(void) -{ - if (on(PAM_MALLOC_PAUSE)) { - if (on(0)) err(("pause requested")); - sleep(pam_malloc_delay_length); - } - - if (on(PAM_MALLOC_STOP)) { - if (on(0)) err(("stop requested")); - exit(1); - } -} - -/* - * here are the memory pointer registering functions.. these actually - * use malloc(!) but that's ok! ;^) - */ - -struct reference { - void *ptr; /* pointer */ - int nelements; /* number of elements */ - int size; /* - each of this size */ - char *file; /* where it was requested - filename */ - char *function; /* - function */ - int line; /* - line number */ -/* - * linking info - */ - struct reference *next; -}; - -static void _dump(const char *say, const struct reference *ref) -{ - _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>" - , say - , ref->ptr,ref->nelements,ref->size - , ref->function,ref->file,ref->line); -} - -static struct reference *root=NULL; - -static char *_strdup(const char *x) -{ - char *s; - - s = (char *)malloc(strlen(x)+1); - if (s == NULL) { - if (on(0)) err(("_strdup failed")); - exit(1); - } - - strcpy(s,x); - return s; -} - -static void add_new_ref(void *new, int n, int size) -{ - struct reference *ref=NULL; - - ref = (struct reference *) malloc( sizeof(struct reference) ); - if (new == NULL || ref == NULL) { - if (on(0)) err(("internal error {add_new_ref}")); - exit(1); - } - - ref->ptr = new; - ref->nelements = n; - ref->size = size; - - ref->file = _strdup(last_file); - ref->function = _strdup(last_call); - ref->line = last_line; - - ref->next = root; - - if (on(PAM_MALLOC_REQUEST)) { - _dump("new_ptr", ref); - } - - root = ref; -} - -static void del_old_ref(void *old) -{ - struct reference *this,*last; - - if (old == NULL) { - if (on(0)) err(("internal error {del_old_ref}")); - exit(1); - } - - /* locate old pointer */ - - last = NULL; - this = root; - while (this) { - if (this->ptr == old) - break; - last = this; - this = this->next; - } - - /* Did we find a reference ? */ - - if (this) { - if (on(PAM_MALLOC_FREE)) { - _dump("free old_ptr", this); - } - if (last == NULL) { - root = this->next; - } else { - last->next = this->next; - } - free(this->file); - free(this->function); - free(this); - } else { - if (on(0)) err(("ERROR!: bad memory")); - hinder(); - } -} - -static void verify_old_ref(void *old) -{ - struct reference *this; - - if (old == NULL) { - if (on(0)) err(("internal error {verify_old_ref}")); - exit(1); - } - - /* locate old pointer */ - - this = root; - while (this) { - if (this->ptr == old) - break; - this = this->next; - } - - /* Did we find a reference ? */ - - if (this) { - if (on(PAM_MALLOC_VERIFY)) { - _dump("verify_ptr", this); - } - } else { - if (on(0)) err(("ERROR!: bad request")); - hinder(); - } -} - -static void dump_memory_list(const char *dump) -{ - struct reference *this; - - this = root; - if (this) { - if (on(0)) err(("un-free()'d memory")); - while (this) { - _dump(dump, this); - this = this->next; - } - } else { - if (on(0)) err(("no memory allocated")); - } -} - -/* now for the wrappers */ - -#define _fn(x) set_last_(x,file,fn,line) - -void *pam_malloc(size_t size, const char *file, const char *fn, const int line) -{ - void *new; - - _fn("malloc"); - - if (on(PAM_MALLOC_FUNC)) err(("request for %d", size)); - - new = malloc(size); - if (new == NULL) { - if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); - } else { - if (on(PAM_MALLOC_REQUEST)) err(("request new")); - add_new_ref(new, 1, size); - } - - return new; -} - -void *pam_calloc(size_t nelm, size_t size - , const char *file, const char *fn, const int line) -{ - void *new; - - _fn("calloc"); - - if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size)); - - new = calloc(nelm,size); - if (new == NULL) { - if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); - } else { - if (on(PAM_MALLOC_REQUEST)) err(("request new")); - add_new_ref(new, nelm, size); - } - - return new; -} - -void pam_free(void *ptr - , const char *file, const char *fn, const int line) -{ - _fn("free"); - - if (on(PAM_MALLOC_FUNC)) - err(("request (%s:%s():%d) to free %p", file, fn, line, ptr)); - - if (ptr == NULL) { - if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer")); - } else { - if (on(PAM_MALLOC_FREE)) err(("deleted old")); - del_old_ref(ptr); - free(ptr); - } -} - -void *pam_memalign(size_t ali, size_t size - , const char *file, const char *fn, const int line) -{ - _fn("memalign"); - if (on(0)) err(("not implemented currently (Sorry)")); - exit(1); -} - -void *pam_realloc(void *ptr, size_t size - , const char *file, const char *fn, const int line) -{ - void *new; - - _fn("realloc"); - - if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size)); - - if (ptr == NULL) { - if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer")); - } else { - verify_old_ref(ptr); - } - - new = realloc(ptr, size); - if (new == NULL) { - if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); - } else { - if (ptr) { - if (on(PAM_MALLOC_FREE)) err(("deleted old")); - del_old_ref(ptr); - } else { - if (on(PAM_MALLOC_NULL)) err(("old is NULL")); - } - if (on(PAM_MALLOC_REQUEST)) err(("request new")); - add_new_ref(new, 1, size); - } - - return new; -} - -void *pam_valloc(size_t size - , const char *file, const char *fn, const int line) -{ - _fn("valloc"); - if (on(0)) err(("not implemented currently (Sorry)")); - exit(1); -} - -#include <alloca.h> - -void *pam_alloca(size_t size - , const char *file, const char *fn, const int line) -{ - _fn("alloca"); - if (on(0)) err(("not implemented currently (Sorry)")); - exit(1); -} - -void pam_exit(int i - , const char *file, const char *fn, const int line) -{ - D(("time to exit")); - - _fn("exit"); - - if (on(0)) err(("passed (%d)", i)); - if (on(PAM_MALLOC_LEAKED)) { - dump_memory_list("leaked"); - } - exit(i); -} - -char *pam_strdup(const char *orig, - const char *file, const char *fn, const int line) -{ - char *new; - - _fn("strdup"); - - if (on(PAM_MALLOC_FUNC)) err(("request for dup of [%s]", orig)); - - new = strdup(orig); - if (new == NULL) { - if (on(PAM_MALLOC_FAIL)) err(("returned NULL")); - } else { - if (on(PAM_MALLOC_REQUEST)) err(("request dup of [%s]", orig)); - add_new_ref(new, 1, strlen(new)+1); - } - - return new; -} - -/* end of file */ diff --git a/libpam/pam_map.c b/libpam/pam_map.c deleted file mode 100644 index b27bb32b..00000000 --- a/libpam/pam_map.c +++ /dev/null @@ -1,78 +0,0 @@ -/* pam_map.c - PAM mapping interface - * - * $Id$ - * - * This is based on the X/Open XSSO specification of March 1997. - * It is not implemented as it is going to change... after 1997/9/25. - * - */ - -#include <stdio.h> - -#include "pam_private.h" - -/* p 54 */ - -int pam_get_mapped_authtok(pam_handle_t *pamh, - const char *target_module_username, - const char *target_module_type, - const char *target_authn_domain, - size_t *target_authtok_len - unsigned char **target_module_authtok); -{ - D(("called")); - - IF_NO_PAMH("pam_get_mapped_authtok",pamh,PAM_SYSTEM_ERR); - - return PAM_SYSTEM_ERROR; -} - -/* p 68 */ - -int pam_set_mapped_authtok(pam_handle_t *pamh, - char *target_module_username, - size_t *target_authtok_len, - unsigned char *target_module_authtok, - char *target_module_type, - char *target_authn_domain) -{ - D(("called")); - - IF_NO_PAMH("pam_set_mapped_authtok",pamh,PAM_SYSTEM_ERR); - - return PAM_SYSTEM_ERROR; -} - -/* p 56 */ - -int pam_get_mapped_username(pam_handle_t *pamh, - const char *src_username, - const char *src_module_type, - const char *src_authn_domain, - const char *target_module_type, - const char *target_authn_domain, - char **target_module_username) -{ - D(("called")); - - IF_NO_PAMH("pam_get_mapped_username",pamh,PAM_SYSTEM_ERR); - - return PAM_SYSTEM_ERROR; -} - -/* p 70 */ - -int pam_set_mapped_username(pam_handle_t *pamh, - char *src_username, - char *src_module_type, - char *src_authn_domain, - char *target_module_username, - char *target_module_type, - char *target_authn_domain) -{ - D(("called")); - - IF_NO_PAMH("pam_set_mapped_username",pamh,PAM_SYSTEM_ERR); - - return PAM_SYSTEM_ERROR; -} diff --git a/libpam/pam_misc.c b/libpam/pam_misc.c deleted file mode 100644 index bd4ed958..00000000 --- a/libpam/pam_misc.c +++ /dev/null @@ -1,321 +0,0 @@ -/* pam_misc.c -- This is random stuff */ - -/* - * $Id$ - */ - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <ctype.h> - -#include "pam_private.h" - -/* caseless string comparison: POSIX does not define this.. */ -int _pam_strCMP(const char *s, const char *t) -{ - int cf; - - do { - cf = tolower(*s) - tolower(*t); - ++t; - } while (!cf && *s++); - - return cf; -} - -char *_pam_StrTok(char *from, const char *format, char **next) -/* - * this function is a variant of the standard strtok, it differs in that - * it takes an additional argument and doesn't nul terminate tokens until - * they are actually reached. - */ -{ - char table[256], *end; - int i; - - if (from == NULL && (from = *next) == NULL) - return from; - - /* initialize table */ - for (i=1; i<256; table[i++] = '\0'); - for (i=0; format[i] ; table[(int)format[i++]] = 'y'); - - /* look for first non-format char */ - while (*from && table[(int)*from]) { - ++from; - } - - if (*from == '[') { - /* - * special case, "[...]" is considered to be a single - * object. Note, however, if one of the format[] chars is - * '[' this single string will not be read correctly. - * Note, any '[' inside the outer "[...]" pair will survive. - * Note, the first ']' will terminate this string, but - * that "\]" will get compressed into "]". That is: - * - * "[..[..\]..]..." --> "..[..].." - */ - char *to; - for (to=end=++from; *end && *end != ']'; ++to, ++end) { - if (*end == '\\' && end[1] == ']') - ++end; - if (to != end) { - *to = *end; - } - } - if (to != end) { - *to = '\0'; - } - /* note, this string is stripped of its edges: "..." is what - remains */ - } else if (*from) { - /* simply look for next blank char */ - for (end=from; *end && !table[(int)*end]; ++end); - } else { - return (*next = NULL); /* no tokens left */ - } - - /* now terminate what we have */ - if (*end) - *end++ = '\0'; - - /* indicate what it left */ - if (*end) { - *next = end; - } else { - *next = NULL; /* have found last token */ - } - - /* return what we have */ - return from; -} - -/* - * Safe duplication of character strings. "Paranoid"; don't leave - * evidence of old token around for later stack analysis. - */ - -char *_pam_strdup(const char *x) -{ - register char *new=NULL; - - if (x != NULL) { - register int i; - - for (i=0; x[i]; ++i); /* length of string */ - if ((new = malloc(++i)) == NULL) { - i = 0; - _pam_system_log(LOG_CRIT, "_pam_strdup: failed to get memory"); - } else { - while (i-- > 0) { - new[i] = x[i]; - } - } - x = NULL; - } - - return new; /* return the duplicate or NULL on error */ -} - -/* Generate argv, argc from s */ -/* caller must free(argv) */ - -int _pam_mkargv(char *s, char ***argv, int *argc) -{ - int l; - int argvlen = 0; - char *sbuf, *sbuf_start; - char **our_argv = NULL; - char **argvbuf; - char *argvbufp; -#ifdef DEBUG - int count=0; -#endif - - D(("_pam_mkargv called: %s",s)); - - *argc = 0; - - l = strlen(s); - if (l) { - if ((sbuf = sbuf_start = _pam_strdup(s)) == NULL) { - _pam_system_log(LOG_CRIT, - "pam_mkargv: null returned by _pam_strdup"); - D(("arg NULL")); - } else { - /* Overkill on the malloc, but not large */ - argvlen = (l + 1) * ((sizeof(char)) + sizeof(char *)); - if ((our_argv = argvbuf = malloc(argvlen)) == NULL) { - _pam_system_log(LOG_CRIT, - "pam_mkargv: null returned by malloc"); - } else { - char *tmp=NULL; - - argvbufp = (char *) argvbuf + (l * sizeof(char *)); - D(("[%s]",sbuf)); - while ((sbuf = _pam_StrTok(sbuf, " \n\t", &tmp))) { - D(("arg #%d",++count)); - D(("->[%s]",sbuf)); - strcpy(argvbufp, sbuf); - D(("copied token")); - *argvbuf = argvbufp; - argvbufp += strlen(argvbufp) + 1; - D(("stepped in argvbufp")); - (*argc)++; - argvbuf++; - sbuf = NULL; - D(("loop again?")); - } - _pam_drop(sbuf_start); - } - } - } - - *argv = our_argv; - - D(("_pam_mkargv returned")); - - return(argvlen); -} - -/* - * this function is used to protect the modules from accidental or - * semi-mallicious harm that an application may do to confuse the API. - */ - -void _pam_sanitize(pam_handle_t *pamh) -{ - int old_caller_is = pamh->caller_is; - - /* - * this is for security. We reset the auth-tokens here. - */ - __PAM_TO_MODULE(pamh); - pam_set_item(pamh, PAM_AUTHTOK, NULL); - pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); - pamh->caller_is = old_caller_is; -} - -/* - * This function scans the array and replaces the _PAM_ACTION_UNDEF - * entries with the default action. - */ - -void _pam_set_default_control(int *control_array, int default_action) -{ - int i; - - for (i=0; i<_PAM_RETURN_VALUES; ++i) { - if (control_array[i] == _PAM_ACTION_UNDEF) { - control_array[i] = default_action; - } - } -} - -/* - * This function is used to parse a control string. This string is a - * series of tokens of the following form: - * - * "[ ]*return_code[ ]*=[ ]*action/[ ]". - */ - -#include "pam_tokens.h" - -void _pam_parse_control(int *control_array, char *tok) -{ - const char *error; - int ret; - - while (*tok) { - int act, len; - - /* skip leading space */ - while (isspace((int)*tok) && *++tok); - if (!*tok) - break; - - /* identify return code */ - for (ret=0; ret<=_PAM_RETURN_VALUES; ++ret) { - len = strlen(_pam_token_returns[ret]); - if (!strncmp(_pam_token_returns[ret], tok, len)) { - break; - } - } - if (ret > _PAM_RETURN_VALUES || !*(tok += len)) { - error = "expecting return value"; - goto parse_error; - } - - /* observe '=' */ - while (isspace((int)*tok) && *++tok); - if (!*tok || *tok++ != '=') { - error = "expecting '='"; - goto parse_error; - } - - /* skip leading space */ - while (isspace((int)*tok) && *++tok); - if (!*tok) { - error = "expecting action"; - goto parse_error; - } - - /* observe action type */ - for (act=0; act < (-(_PAM_ACTION_UNDEF)); ++act) { - len = strlen(_pam_token_actions[act]); - if (!strncmp(_pam_token_actions[act], tok, len)) { - act *= -1; - tok += len; - break; - } - } - if (act > 0) { - /* - * Either we have a number or we have hit an error. In - * principle, there is nothing to stop us accepting - * negative offsets. (Although we would have to think of - * another way of encoding the tokens.) However, I really - * think this would be both hard to administer and easily - * cause looping problems. So, for now, we will just - * allow forward jumps. (AGM 1998/1/7) - */ - if (!isdigit((int)*tok)) { - error = "expecting jump number"; - goto parse_error; - } - /* parse a number */ - act = 0; - do { - act *= 10; - act += *tok - '0'; /* XXX - this assumes ascii behavior */ - } while (*++tok && isdigit((int)*tok)); - if (! act) { - /* we do not allow 0 jumps. There is a token ('ignore') - for that */ - error = "expecting non-zero"; - goto parse_error; - } - } - - /* set control_array element */ - if (ret != _PAM_RETURN_VALUES) { - control_array[ret] = act; - } else { - /* set the default to 'act' */ - _pam_set_default_control(control_array, act); - } - } - - /* that was a success */ - return; - -parse_error: - /* treat everything as bad */ - _pam_system_log(LOG_ERR, "pam_parse: %s; [...%s]", error, tok); - for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD); - -} diff --git a/libpam/pam_password.c b/libpam/pam_password.c deleted file mode 100644 index 8e36971e..00000000 --- a/libpam/pam_password.c +++ /dev/null @@ -1,57 +0,0 @@ -/* pam_password.c - PAM Password Management */ - -/* - * $Id$ - */ - -#include <stdio.h> -#include <stdlib.h> - -/* #define DEBUG */ - -#include "pam_private.h" - -int pam_chauthtok(pam_handle_t *pamh, int flags) -{ - int retval; - - D(("called.")); - - IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - if (pamh->former.choice == PAM_NOT_STACKED) { - _pam_start_timer(pamh); /* we try to make the time for a failure - independent of the time it takes to - fail */ - _pam_sanitize(pamh); - pamh->former.update = PAM_FALSE; - } - - /* first call to check if there will be a problem */ - if (pamh->former.update || - (retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK, - PAM_CHAUTHTOK)) == PAM_SUCCESS) { - D(("completed check ok: former=%d", pamh->former.update)); - pamh->former.update = PAM_TRUE; - retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK, - PAM_CHAUTHTOK); - } - - /* if we completed we should clean up */ - if (retval != PAM_INCOMPLETE) { - _pam_sanitize(pamh); - pamh->former.update = PAM_FALSE; - _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ - D(("pam_chauthtok exit %d - %d", retval, pamh->former.choice)); - } else { - D(("will resume when ready", retval)); - } - - return retval; -} - diff --git a/libpam/pam_private.h b/libpam/pam_private.h deleted file mode 100644 index 7afc4fa7..00000000 --- a/libpam/pam_private.h +++ /dev/null @@ -1,328 +0,0 @@ -/* - * pam_private.h - * - * $Id$ - * - * This is the Linux-PAM Library Private Header. It contains things - * internal to the Linux-PAM library. Things not needed by either an - * application or module. - * - * Please see end of file for copyright. - * - * Creator: Marc Ewing. - * Maintained: CVS - */ - -#ifndef _PAM_PRIVATE_H -#define _PAM_PRIVATE_H - -#include <security/_pam_aconf.h> - -/* this is not used at the moment --- AGM */ -#define LIBPAM_VERSION (LIBPAM_VERSION_MAJOR*0x100 + LIBPAM_VERSION_MINOR) - -#include <security/pam_appl.h> -#include <security/pam_modules.h> - -/* the Linux-PAM configuration file */ - -#define PAM_CONFIG "/etc/pam.conf" -#define PAM_CONFIG_D "/etc/pam.d" -#define PAM_CONFIG_DF "/etc/pam.d/%s" - -#define PAM_DEFAULT_SERVICE "other" /* lower case */ -#define PAM_DEFAULT_SERVICE_FILE PAM_CONFIG_D "/" PAM_DEFAULT_SERVICE - -#ifdef PAM_LOCKING -/* - * the Linux-PAM lock file. If it exists Linux-PAM will abort. Use it - * to block access to libpam - */ -#define PAM_LOCK_FILE "/var/lock/subsys/PAM" -#endif - -/* components of the pam_handle structure */ - -#define _PAM_INVALID_RETVAL -1 /* default value for cached_retval */ - -struct handler { - int must_fail; - int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv); - int actions[_PAM_RETURN_VALUES]; - /* set by authenticate, open_session, chauthtok(1st) - consumed by setcred, close_session, chauthtok(2nd) */ - int cached_retval; int *cached_retval_p; - int argc; - char **argv; - struct handler *next; -}; - -struct loaded_module { - char *name; - int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */ - void *dl_handle; -}; - -#define PAM_MT_DYNAMIC_MOD 0 -#define PAM_MT_STATIC_MOD 1 -#define PAM_MT_FAULTY_MOD 2 - -struct handlers { - struct handler *authenticate; - struct handler *setcred; - struct handler *acct_mgmt; - struct handler *open_session; - struct handler *close_session; - struct handler *chauthtok; -}; - -struct service { - struct loaded_module *module; /* Only used for dynamic loading */ - int modules_allocated; - int modules_used; - int handlers_loaded; - - struct handlers conf; /* the configured handlers */ - struct handlers other; /* the default handlers */ -}; - -/* - * Environment helper functions - */ - -#define PAM_ENV_CHUNK 10 /* chunks of memory calloc()'d * - * at once */ - -struct pam_environ { - int entries; /* the number of pointers available */ - int requested; /* the number of pointers used: * - * 1 <= requested <= entries */ - char **list; /* the environment storage (a list * - * of pointers to malloc() memory) */ -}; - -#include <sys/time.h> - -typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean; - -struct _pam_fail_delay { - _pam_boolean set; - unsigned int delay; - time_t begin; - const void *delay_fn_ptr; -}; - -struct _pam_former_state { -/* this is known and set by _pam_dispatch() */ - int choice; /* which flavor of module function did we call? */ - -/* state info for the _pam_dispatch_aux() function */ - int depth; /* how deep in the stack were we? */ - int impression; /* the impression at that time */ - int status; /* the status before returning incomplete */ - -/* state info used by pam_get_user() function */ - int want_user; - char *prompt; /* saved prompt information */ - -/* state info for the pam_chauthtok() function */ - _pam_boolean update; -}; - -struct pam_handle { - char *authtok; - unsigned caller_is; - struct pam_conv *pam_conversation; - char *oldauthtok; - char *prompt; /* for use by pam_get_user() */ - char *service_name; - char *user; - char *rhost; - char *ruser; - char *tty; - struct pam_data *data; - struct pam_environ *env; /* structure to maintain environment list */ - struct _pam_fail_delay fail_delay; /* helper function for easy delays */ - struct service handlers; - struct _pam_former_state former; /* library state - support for - event driven applications */ -}; - -/* Values for select arg to _pam_dispatch() */ -#define PAM_NOT_STACKED 0 -#define PAM_AUTHENTICATE 1 -#define PAM_SETCRED 2 -#define PAM_ACCOUNT 3 -#define PAM_OPEN_SESSION 4 -#define PAM_CLOSE_SESSION 5 -#define PAM_CHAUTHTOK 6 - -#define _PAM_ACTION_IS_JUMP(x) ((x) > 0) -#define _PAM_ACTION_IGNORE 0 -#define _PAM_ACTION_OK -1 -#define _PAM_ACTION_DONE -2 -#define _PAM_ACTION_BAD -3 -#define _PAM_ACTION_DIE -4 -#define _PAM_ACTION_RESET -5 -/* Add any new entries here. Will need to change ..._UNDEF and then - * need to change pam_tokens.h */ -#define _PAM_ACTION_UNDEF -6 /* this is treated as an error - ( = _PAM_ACTION_BAD) */ - -/* character tables for parsing config files */ -extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF]; -extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1]; - -/* - * internally defined functions --- these should not be directly - * called by applications or modules - */ -int _pam_dispatch(pam_handle_t *pamh, int flags, int choice); - -/* Free various allocated structures and dlclose() the libs */ -int _pam_free_handlers(pam_handle_t *pamh); - -/* Parse config file, allocate handler structures, dlopen() */ -int _pam_init_handlers(pam_handle_t *pamh); - -/* Set all hander stuff to 0/NULL - called once from pam_start() */ -void _pam_start_handlers(pam_handle_t *pamh); - -/* environment helper functions */ - -/* create the environment structure */ -int _pam_make_env(pam_handle_t *pamh); - -/* delete the environment structure */ -void _pam_drop_env(pam_handle_t *pamh); - -/* these functions deal with failure delays as required by the - authentication modules and application. Their *interface* is likely - to remain the same although their function is hopefully going to - improve */ - -/* reset the timer to no-delay */ -void _pam_reset_timer(pam_handle_t *pamh); - -/* this sets the clock ticking */ -void _pam_start_timer(pam_handle_t *pamh); - -/* this waits for the clock to stop ticking if status != PAM_SUCCESS */ -void _pam_await_timer(pam_handle_t *pamh, int status); - -typedef void (*voidfunc(void))(void); -#ifdef PAM_STATIC - -/* The next two in ../modules/_pam_static/pam_static.c */ - -/* Return pointer to data structure used to define a static module */ -struct pam_module * _pam_open_static_handler(const char *path); - -/* Return pointer to function requested from static module */ - -voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname); - -#endif - -/* For now we just use a stack and linear search for module data. */ -/* If it becomes apparent that there is a lot of data, it should */ -/* changed to either a sorted list or a hash table. */ - -struct pam_data { - char *name; - void *data; - void (*cleanup)(pam_handle_t *pamh, void *data, int error_status); - struct pam_data *next; -}; - -void _pam_free_data(pam_handle_t *pamh, int status); - -int _pam_strCMP(const char *s, const char *t); -char *_pam_StrTok(char *from, const char *format, char **next); - -char *_pam_strdup(const char *s); - -int _pam_mkargv(char *s, char ***argv, int *argc); - -void _pam_sanitize(pam_handle_t *pamh); - -void _pam_set_default_control(int *control_array, int default_action); - -void _pam_parse_control(int *control_array, char *tok); - -void _pam_system_log(int priority, const char *format, ... ); -#define _PAM_SYSTEM_LOG_PREFIX "PAM " - -/* - * XXX - Take care with this. It could confuse the logic of a trailing - * else - */ - -#define IF_NO_PAMH(X,pamh,ERR) \ -if ((pamh) == NULL) { \ - _pam_system_log(LOG_ERR, X ": NULL pam handle passed"); \ - return ERR; \ -} - -/* Definition for the default username prompt used by pam_get_user() */ - -#define PAM_DEFAULT_PROMPT "Please enter username: " - -/* - * include some helpful macros - */ - -#include <security/_pam_macros.h> - -/* used to work out where control currently resides (in an application - or in a module) */ - -#define _PAM_CALLED_FROM_MODULE 1 -#define _PAM_CALLED_FROM_APP 2 - -#define __PAM_FROM_MODULE(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_MODULE) -#define __PAM_FROM_APP(pamh) ((pamh)->caller_is == _PAM_CALLED_FROM_APP) -#define __PAM_TO_MODULE(pamh) \ - do { (pamh)->caller_is = _PAM_CALLED_FROM_MODULE; } while (0) -#define __PAM_TO_APP(pamh) \ - do { (pamh)->caller_is = _PAM_CALLED_FROM_APP; } while (0) - -/* - * Copyright (C) 1995 by Red Hat Software, Marc Ewing - * Copyright (c) 1996-8,2001 by Andrew G. Morgan <morgan@kernel.org> - * - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#endif /* _PAM_PRIVATE_H_ */ diff --git a/libpam/pam_second.c b/libpam/pam_second.c deleted file mode 100644 index 31bdc6cb..00000000 --- a/libpam/pam_second.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * pam_second.c -- PAM secondary authentication - * (based on XSSO draft spec of March 1997) - * - * $Id$ - * - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "pam_private.h" - -/* p 42 */ - -/* XXX - there are actually no plans to support this function. It does - not appear to be very well defined */ - -int pam_authenticate_secondary(pam_handle_t *pamh, - char *target_username, - char *target_module_type, - char *target_authn_domain, - char *target_supp_data, - unsigned char *target_module_authtok, - int flags); - -int pam_authenticate_secondary(pam_handle_t *pamh, - char *target_username, - char *target_module_type, - char *target_authn_domain, - char *target_supp_data, - unsigned char *target_module_authtok, - int flags) -{ - int retval=PAM_SYSTEM_ERR; - - D(("called")); - - _pam_start_timer(pamh); /* we try to make the time for a failure - independent of the time it takes to - fail */ - - IF_NO_PAMH("pam_authenticate_secondary",pamh,PAM_SYSTEM_ERR); - - _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */ - - D(("pam_authenticate_secondary exit")); - - return retval; -} diff --git a/libpam/pam_session.c b/libpam/pam_session.c deleted file mode 100644 index 16b021df..00000000 --- a/libpam/pam_session.c +++ /dev/null @@ -1,37 +0,0 @@ -/* pam_session.c - PAM Session Management */ - -/* - * $Id$ - */ - -#include <stdio.h> - -#include "pam_private.h" - -int pam_open_session(pam_handle_t *pamh, int flags) -{ - D(("called")); - - IF_NO_PAMH("pam_open_session", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - return _pam_dispatch(pamh, flags, PAM_OPEN_SESSION); -} - -int pam_close_session(pam_handle_t *pamh, int flags) -{ - D(("called")); - - IF_NO_PAMH("pam_close_session", pamh, PAM_SYSTEM_ERR); - - if (__PAM_FROM_MODULE(pamh)) { - D(("called from module!?")); - return PAM_SYSTEM_ERR; - } - - return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION); -} diff --git a/libpam/pam_start.c b/libpam/pam_start.c deleted file mode 100644 index 0e50bb40..00000000 --- a/libpam/pam_start.c +++ /dev/null @@ -1,112 +0,0 @@ -/* pam_start.c */ - -/* Creator Marc Ewing - * Maintained by AGM - * - * $Id$ - * - */ - -#include <ctype.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <syslog.h> - -#include "pam_private.h" - -int pam_start ( - const char *service_name, - const char *user, - const struct pam_conv *pam_conversation, - pam_handle_t **pamh) -{ - D(("called pam_start: [%s] [%s] [%p] [%p]" - ,service_name, user, pam_conversation, pamh)); - - if ((*pamh = calloc(1, sizeof(**pamh))) == NULL) { - _pam_system_log(LOG_CRIT, "pam_start: calloc failed for *pamh"); - return (PAM_BUF_ERR); - } - - /* Mark the caller as the application - permission to do certain - things is limited to a module or an application */ - - __PAM_TO_APP(*pamh); - - if (service_name) { - char *tmp; - - if (((*pamh)->service_name = _pam_strdup(service_name)) == NULL) { - _pam_system_log(LOG_CRIT, - "pam_start: _pam_strdup failed for service name"); - _pam_drop(*pamh); - return (PAM_BUF_ERR); - } - for (tmp=(*pamh)->service_name; *tmp; ++tmp) - *tmp = tolower(*tmp); /* require lower case */ - } else - (*pamh)->service_name = NULL; - - if (user) { - if (((*pamh)->user = _pam_strdup(user)) == NULL) { - _pam_system_log(LOG_CRIT, - "pam_start: _pam_strdup failed for user"); - _pam_drop((*pamh)->service_name); - _pam_drop(*pamh); - return (PAM_BUF_ERR); - } - } else - (*pamh)->user = NULL; - - (*pamh)->tty = NULL; - (*pamh)->prompt = NULL; /* prompt for pam_get_user() */ - (*pamh)->ruser = NULL; - (*pamh)->rhost = NULL; - (*pamh)->authtok = NULL; - (*pamh)->oldauthtok = NULL; - (*pamh)->fail_delay.delay_fn_ptr = NULL; - (*pamh)->former.choice = PAM_NOT_STACKED; - - if (pam_conversation == NULL - || ((*pamh)->pam_conversation = (struct pam_conv *) - malloc(sizeof(struct pam_conv))) == NULL) { - _pam_system_log(LOG_CRIT, "pam_start: malloc failed for pam_conv"); - _pam_drop((*pamh)->service_name); - _pam_drop((*pamh)->user); - _pam_drop(*pamh); - return (PAM_BUF_ERR); - } else { - memcpy((*pamh)->pam_conversation, pam_conversation, - sizeof(struct pam_conv)); - } - - (*pamh)->data = NULL; - if ( _pam_make_env(*pamh) != PAM_SUCCESS ) { - _pam_system_log(LOG_ERR,"pam_start: failed to initialize environment"); - _pam_drop((*pamh)->service_name); - _pam_drop((*pamh)->user); - _pam_drop(*pamh); - return PAM_ABORT; - } - - _pam_reset_timer(*pamh); /* initialize timer support */ - - _pam_start_handlers(*pamh); /* cannot fail */ - - /* According to the SunOS man pages, loading modules and resolving - * symbols happens on the first call from the application. */ - - if ( _pam_init_handlers(*pamh) != PAM_SUCCESS ) { - _pam_system_log(LOG_ERR, "pam_start: failed to initialize handlers"); - _pam_drop_env(*pamh); /* purge the environment */ - _pam_drop((*pamh)->service_name); - _pam_drop((*pamh)->user); - _pam_drop(*pamh); - return PAM_ABORT; - } - - D(("exiting pam_start successfully")); - - return PAM_SUCCESS; -} diff --git a/libpam/pam_static.c b/libpam/pam_static.c deleted file mode 100644 index 64a3dd31..00000000 --- a/libpam/pam_static.c +++ /dev/null @@ -1,141 +0,0 @@ -/* pam_static.c -- static module loading helper functions */ - -/* created by Michael K. Johnson, johnsonm@redhat.com - * - * $Id$ - */ - -/* This whole file is only used for PAM_STATIC */ - -#ifdef PAM_STATIC - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "pam_private.h" - -/* - * Need to include pointers to static modules; this was built by each - * of the modules that register... - */ - -#include "../modules/_static_module_list" - -/* - * and here is a structure that connects libpam to the above static - * modules - */ - -static struct pam_module *static_modules[] = { - -#include "../modules/_static_module_entry" - - NULL -}; - -/* - * and now for the functions - */ - -/* Return pointer to data structure used to define a static module */ -struct pam_module * _pam_open_static_handler(const char *path) -{ - int i; - const char *clpath = path; - char *lpath, *end; - - if (strchr(clpath, '/')) { - /* ignore path and leading "/" */ - clpath = strrchr(lpath, '/') + 1; - } - /* create copy to muck with (must free before return) */ - lpath = _pam_strdup(clpath); - /* chop .so off copy if it exists (or other extension on other - platform...) */ - end = strstr(lpath, ".so"); - if (end) { - *end = '\0'; - } - - /* now go find the module */ - for (i = 0; static_modules[i] != NULL; i++) { - D(("%s=?%s\n", lpath, static_modules[i]->name)); - if (static_modules[i]->name && - ! strcmp(static_modules[i]->name, lpath)) { - break; - } - } - - if (static_modules[i] == NULL) { - _pam_system_log(NULL, NULL, LOG_ERR, "no static module named %s", - lpath); - } - - free(lpath); - return (static_modules[i]); -} - -/* Return pointer to function requested from static module - * Can't just return void *, because ANSI C disallows casting a - * pointer to a function to a void *... - * This definition means: - * _pam_get_static_sym is a function taking two arguments and - * returning a pointer to a function which takes no arguments - * and returns void... */ -voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname) { - - if (! strcmp(symname, "pam_sm_authenticate")) { - return ((voidfunc *)mod->pam_sm_authenticate); - } else if (! strcmp(symname, "pam_sm_setcred")) { - return ((voidfunc *)mod->pam_sm_setcred); - } else if (! strcmp(symname, "pam_sm_acct_mgmt")) { - return ((voidfunc *)mod->pam_sm_acct_mgmt); - } else if (! strcmp(symname, "pam_sm_open_session")) { - return ((voidfunc *)mod->pam_sm_open_session); - } else if (! strcmp(symname, "pam_sm_close_session")) { - return ((voidfunc *)mod->pam_sm_close_session); - } else if (! strcmp(symname, "pam_sm_chauthtok")) { - return ((voidfunc *)mod->pam_sm_chauthtok); - } - /* getting to this point is an error */ - return ((voidfunc *)NULL); -} - -#endif /* PAM_STATIC */ - -/* - * Copyright (C) 1995 by Red Hat Software, Michael K. Johnson - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/libpam/pam_strerror.c b/libpam/pam_strerror.c deleted file mode 100644 index de857fd8..00000000 --- a/libpam/pam_strerror.c +++ /dev/null @@ -1,93 +0,0 @@ -/* pam_strerror.c */ - -/* - * $Id$ - */ - -#include "pam_private.h" - -const char *pam_strerror(pam_handle_t *pamh, int errnum) -{ -#ifdef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT /* will be removed from v 1.0 */ - - int possible_error; - - possible_error = (int) pamh; - if (!(possible_error >= 0 && possible_error <= PAM_BAD_ITEM)) { - possible_error = errnum; - } - -/* mask standard behavior to use possible_error variable. */ -#define errnum possible_error - -#endif /* UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT */ - - switch (errnum) { - case PAM_SUCCESS: - return "Success"; - case PAM_ABORT: - return "Critical error - immediate abort"; - case PAM_OPEN_ERR: - return "dlopen() failure"; - case PAM_SYMBOL_ERR: - return "Symbol not found"; - case PAM_SERVICE_ERR: - return "Error in service module"; - case PAM_SYSTEM_ERR: - return "System error"; - case PAM_BUF_ERR: - return "Memory buffer error"; - case PAM_PERM_DENIED: - return "Permission denied"; - case PAM_AUTH_ERR: - return "Authentication failure"; - case PAM_CRED_INSUFFICIENT: - return "Insufficient credentials to access authentication data"; - case PAM_AUTHINFO_UNAVAIL: - return "Authentication service cannot retrieve authentication info."; - case PAM_USER_UNKNOWN: - return "User not known to the underlying authentication module"; - case PAM_MAXTRIES: - return "Have exhasted maximum number of retries for service."; - case PAM_NEW_AUTHTOK_REQD: - return "Authentication token is no longer valid; new one required."; - case PAM_ACCT_EXPIRED: - return "User account has expired"; - case PAM_SESSION_ERR: - return "Cannot make/remove an entry for the specified session"; - case PAM_CRED_UNAVAIL: - return "Authentication service cannot retrieve user credentials"; - case PAM_CRED_EXPIRED: - return "User credentials expired"; - case PAM_CRED_ERR: - return "Failure setting user credentials"; - case PAM_NO_MODULE_DATA: - return "No module specific data is present"; - case PAM_BAD_ITEM: - return "Bad item passed to pam_*_item()"; - case PAM_CONV_ERR: - return "Conversation error"; - case PAM_AUTHTOK_ERR: - return "Authentication token manipulation error"; - case PAM_AUTHTOK_RECOVER_ERR: - return "Authentication information cannot be recovered"; - case PAM_AUTHTOK_LOCK_BUSY: - return "Authentication token lock busy"; - case PAM_AUTHTOK_DISABLE_AGING: - return "Authentication token aging disabled"; - case PAM_TRY_AGAIN: - return "Failed preliminary check by password service"; - case PAM_IGNORE: - return "Please ignore underlying account module"; - case PAM_MODULE_UNKNOWN: - return "Module is unknown"; - case PAM_AUTHTOK_EXPIRED: - return "Authentication token expired"; - case PAM_CONV_AGAIN: - return "Conversation is waiting for event"; - case PAM_INCOMPLETE: - return "Application needs to call libpam again"; - } - - return "Unknown PAM error"; -} diff --git a/libpam/pam_tokens.h b/libpam/pam_tokens.h deleted file mode 100644 index fad30759..00000000 --- a/libpam/pam_tokens.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * pam_tokens.h - * - * $Id$ - * - * This is a Linux-PAM Library Private Header file. It contains tokens - * that are used when we parse the configuration file(s). - * - * Please see end of file for copyright. - * - * Creator: Andrew Morgan. - * - */ - -#ifndef _PAM_TOKENS_H -#define _PAM_TOKENS_H - -/* an array of actions */ - -const char * const _pam_token_actions[-_PAM_ACTION_UNDEF] = { - "ignore", /* 0 */ - "ok", /* -1 */ - "done", /* -2 */ - "bad", /* -3 */ - "die", /* -4 */ - "reset", /* -5 */ -}; - -/* an array of possible return values */ - -const char * const _pam_token_returns[_PAM_RETURN_VALUES+1] = { - "success", /* 0 */ - "open_err", /* 1 */ - "symbol_err", /* 2 */ - "service_err", /* 3 */ - "system_err", /* 4 */ - "buf_err", /* 5 */ - "perm_denied", /* 6 */ - "auth_err", /* 7 */ - "cred_insufficient", /* 8 */ - "authinfo_unavail", /* 9 */ - "user_unknown", /* 10 */ - "maxtries", /* 11 */ - "new_authtok_reqd", /* 12 */ - "acct_expired", /* 13 */ - "session_err", /* 14 */ - "cred_unavail", /* 15 */ - "cred_expired", /* 16 */ - "cred_err", /* 17 */ - "no_module_data", /* 18 */ - "conv_err", /* 19 */ - "authtok_err", /* 20 */ - "authtok_recover_err", /* 21 */ - "authtok_lock_busy", /* 22 */ - "authtok_disable_aging", /* 23 */ - "try_again", /* 24 */ - "ignore", /* 25 */ - "abort", /* 26 */ - "authtok_expired", /* 27 */ - "module_unknown", /* 28 */ - "bad_item", /* 29 */ - "conv_again", /* 30 */ - "incomplete", /* 31 */ -/* add new return codes here */ - "default" /* this is _PAM_RETURN_VALUES and indicates - the default return action */ -}; - -/* - * Copyright (C) 1998,2001 Andrew G. Morgan <morgan@kernel.org> - * - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#endif /* _PAM_PRIVATE_H_ */ diff --git a/libpam_misc/.cvsignore b/libpam_misc/.cvsignore deleted file mode 100644 index b6cfd742..00000000 --- a/libpam_misc/.cvsignore +++ /dev/null @@ -1,9 +0,0 @@ -libpam_misc.so -libpam_misc.a -libpamd_misc.so -libpamd_misc.a -help_env.o -misc_conv.o -xstrdup.o -dynamic -static diff --git a/libpam_misc/Makefile b/libpam_misc/Makefile deleted file mode 100644 index e9b1a6c1..00000000 --- a/libpam_misc/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# -# $Id$ -# - -# lots of debugging information goes to /tmp/pam-debug.log -#MOREFLAGS += -D"DEBUG" - -include ../Make.Rules - -ifeq ($(WITH_LIBDEBUG),yes) - LIBNAME=libpam_miscd -else - LIBNAME=libpam_misc -endif -VERSION=.$(MAJOR_REL) -MODIFICATION=.$(MINOR_REL) - -CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC) -LINKLIBS += -L$(absolute_objdir)/libpam -lpam - -# dynamic library names - -LIBNAMED = $(LIBNAME).$(DYNTYPE) -LIBNAMEDNAME = $(LIBNAMED)$(VERSION) -LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION) - -# static library name - -LIBNAMEDSTATIC = $(LIBNAME).a - -LIBOBJECTS = help_env.o misc_conv.o - -ifeq ($(DYNAMIC_LIBPAM),yes) -DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS)) -endif - -ifeq ($(STATIC_LIBPAM),yes) -SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS)) -endif - -# --------------------------------------------- -## rules - -all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC) - -dirs: -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) dynamic -endif -ifeq ($(STATIC_LIBPAM),yes) - $(MKDIR) static -endif - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -$(LIBNAMED): $(DLIBOBJECTS) -ifeq ($(DYNAMIC_LIBPAM),yes) - ifeq ($(USESONAME),yes) - $(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) - else - $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) - endif - ifeq ($(NEEDSONAME),yes) - rm -f $(LIBNAMEDFULL) - ln -s $(LIBNAMED) $(LIBNAMEDFULL) - rm -f $(LIBNAMEDNAME) - ln -s $(LIBNAMED) $(LIBNAMEDNAME) - endif -endif - -$(LIBNAMEDSTATIC): $(SLIBOBJECTS) -ifeq ($(STATIC_LIBPAM),yes) - $(AR) rc $@ $(SLIBOBJECTS) $(MODULES) - $(RANLIB) $@ -endif - -install: all - $(MKDIR) $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/pam_misc.h $(FAKEROOT)$(INCLUDED) -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) $(FAKEROOT)$(libdir) - $(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) - $(LDCONFIG) - ifneq ($(DYNTYPE),"sl") - ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) ) - endif -endif -ifeq ($(STATIC_LIBPAM),yes) - $(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir) -endif - -remove: - rm -f $(FAKEROOT)$(INCLUDED)/pam_misc.h - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED) - $(LDCONFIG) - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC) - -clean: - rm -f a.out core *~ static/*.o dynamic/*.o - rm -f *.a *.out *.o *.so ./include/security/*~ - if [ -d dynamic ]; then rmdir dynamic ; fi - if [ -d static ]; then rmdir static ; fi diff --git a/libpam_misc/help_env.c b/libpam_misc/help_env.c deleted file mode 100644 index 9f66156e..00000000 --- a/libpam_misc/help_env.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * $Id$ - * - * This file was written by Andrew G. Morgan <morgan@parc.power.net> - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <security/pam_misc.h> - -/* - * This is a useful function for dumping the Linux-PAM environment - * into some local memory, prior to it all getting lost when pam_end() - * is called. - * - * Initially it was assumed that libpam did not do this part correctly - * (based on a loose email definition). The X/Open XSSO spec makes it - * clear that this function is a duplicate of the one already in - * libpam and therefore unnecessary. IT WILL BE COMPLETELY REMOVED - * IN libpam_misc 1.0 */ - -char **pam_misc_copy_env(pam_handle_t *pamh); -char **pam_misc_copy_env(pam_handle_t *pamh) -{ - return pam_getenvlist(pamh); -} - -/* - * This function should be used to carefully dispose of the copied - * environment. - * - * usage: env = pam_misc_drop_env(env); - */ - -char **pam_misc_drop_env(char **dump) -{ - int i; - - for (i=0; dump[i] != NULL; ++i) { - D(("dump[%d]=`%s'", i, dump[i])); - _pam_overwrite(dump[i]); - _pam_drop(dump[i]); - } - _pam_drop(dump); - - return NULL; -} - -/* - * This function takes the supplied environment and uploads it to be - * the PAM one. - */ - -int pam_misc_paste_env(pam_handle_t *pamh, const char * const * user_env) -{ - for (; user_env && *user_env; ++user_env) { - int retval; - - D(("uploading: %s", *user_env)); - retval = pam_putenv(pamh, *user_env); - if (retval != PAM_SUCCESS) { - D(("error setting %s: %s", *user_env, pam_strerror(pamh,retval))); - return retval; - } - } - D(("done.")); - return PAM_SUCCESS; -} - -/* - * This is a wrapper to make pam behave in the way that setenv() does. - */ - -int pam_misc_setenv(pam_handle_t *pamh, const char *name - , const char *value, int readonly) -{ - char *tmp; - int retval; - - if (readonly) { - const char *etmp; - - /* we check if the variable is there already */ - etmp = pam_getenv(pamh, name); - if (etmp != NULL) { - D(("failed to set readonly variable: %s", name)); - return PAM_PERM_DENIED; /* not allowed to overwrite */ - } - } - tmp = malloc(2+strlen(name)+strlen(value)); - if (tmp != NULL) { - sprintf(tmp,"%s=%s",name,value); - D(("pam_putt()ing: %s", tmp)); - retval = pam_putenv(pamh, tmp); - _pam_overwrite(tmp); /* purge */ - _pam_drop(tmp); /* forget */ - } else { - D(("malloc failure")); - retval = PAM_BUF_ERR; - } - - return retval; -} diff --git a/libpam_misc/include/security/pam_misc.h b/libpam_misc/include/security/pam_misc.h deleted file mode 100644 index 0ec2fdd1..00000000 --- a/libpam_misc/include/security/pam_misc.h +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id$ */ - -#ifndef __PAMMISC_H -#define __PAMMISC_H - -#include <security/pam_appl.h> -#include <security/pam_client.h> - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* include some useful macros */ - -#include <security/_pam_macros.h> - -/* functions defined in pam_misc.* libraries */ - -extern int misc_conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr); - -#include <time.h> - -extern time_t pam_misc_conv_warn_time; /* time that we should warn user */ -extern time_t pam_misc_conv_die_time; /* cut-off time for input */ -extern const char *pam_misc_conv_warn_line; /* warning notice */ -extern const char *pam_misc_conv_die_line; /* cut-off remark */ -extern int pam_misc_conv_died; /* 1 = cut-off time reached (0 not) */ -extern int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p); -extern void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p); -/* - * Environment helper functions - */ - -/* transcribe given environment (to pam) */ -extern int pam_misc_paste_env(pam_handle_t *pamh - , const char * const * user_env); - -/* char **pam_misc_copy_env(pam_handle_t *pamh); - - This is no longer defined as a prototype because the X/Open XSSO - spec makes it clear that PAM's pam_getenvlist() does exactly - what this was needed for. - - A wrapper is still provided in the pam_misc library - so that - legacy applications will still work. But _BE_WARNED_ it will - disappear by the release of libpam 1.0 . */ - -/* delete environment as obtained from (pam_getenvlist) */ -extern char **pam_misc_drop_env(char **env); - -/* provide something like the POSIX setenv function for the (Linux-)PAM - * environment. */ - -extern int pam_misc_setenv(pam_handle_t *pamh, const char *name - , const char *value, int readonly); - -#ifdef __cplusplus -} -#endif /* def __cplusplus */ - -#endif /* ndef __PAMMISC_H */ diff --git a/libpam_misc/misc_conv.c b/libpam_misc/misc_conv.c deleted file mode 100644 index c58a597a..00000000 --- a/libpam_misc/misc_conv.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * $Id$ - * - * A generic conversation function for text based applications - * - * Written by Andrew Morgan <morgan@linux.kernel.org> - */ - -#include <security/_pam_aconf.h> - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <termios.h> -#include <time.h> -#include <unistd.h> - -#include <security/pam_appl.h> -#include <security/pam_misc.h> - -#define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */ -#define CONV_ECHO_ON 1 /* types of echo state */ -#define CONV_ECHO_OFF 0 - -/* - * external timeout definitions - these can be overriden by the - * application. - */ - -time_t pam_misc_conv_warn_time = 0; /* time when we warn */ -time_t pam_misc_conv_die_time = 0; /* time when we timeout */ - -const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n"; -const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n"; - -int pam_misc_conv_died=0; /* application can probe this for timeout */ - -/* - * These functions are for binary prompt manipulation. - * The manner in which a binary prompt is processed is application - * specific, so these function pointers are provided and can be - * initialized by the application prior to the conversation function - * being used. - */ - -static void pam_misc_conv_delete_binary(void *appdata, - pamc_bp_t *delete_me) -{ - PAM_BP_RENEW(delete_me, 0, 0); -} - -int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL; -void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p) - = pam_misc_conv_delete_binary; - -/* the following code is used to get text input */ - -static volatile int expired=0; - -/* return to the previous signal handling */ -static void reset_alarm(struct sigaction *o_ptr) -{ - (void) alarm(0); /* stop alarm clock - if still ticking */ - (void) sigaction(SIGALRM, o_ptr, NULL); -} - -/* this is where we intercept the alarm signal */ -static void time_is_up(int ignore) -{ - expired = 1; -} - -/* set the new alarm to hit the time_is_up() function */ -static int set_alarm(int delay, struct sigaction *o_ptr) -{ - struct sigaction new_sig; - - sigemptyset(&new_sig.sa_mask); - new_sig.sa_flags = 0; - new_sig.sa_handler = time_is_up; - if ( sigaction(SIGALRM, &new_sig, o_ptr) ) { - return 1; /* setting signal failed */ - } - if ( alarm(delay) ) { - (void) sigaction(SIGALRM, o_ptr, NULL); - return 1; /* failed to set alarm */ - } - return 0; /* all seems to have worked */ -} - -/* return the number of seconds to next alarm. 0 = no delay, -1 = expired */ -static int get_delay(void) -{ - time_t now; - - expired = 0; /* reset flag */ - (void) time(&now); - - /* has the quit time past? */ - if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) { - fprintf(stderr,"%s",pam_misc_conv_die_line); - - pam_misc_conv_died = 1; /* note we do not reset the die_time */ - return -1; /* time is up */ - } - - /* has the warning time past? */ - if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) { - fprintf(stderr, "%s", pam_misc_conv_warn_line); - pam_misc_conv_warn_time = 0; /* reset warn_time */ - - /* indicate remaining delay - if any */ - - return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now:0 ); - } - - /* indicate possible warning delay */ - - if (pam_misc_conv_warn_time) - return (pam_misc_conv_warn_time - now); - else if (pam_misc_conv_die_time) - return (pam_misc_conv_die_time - now); - else - return 0; -} - -/* read a line of input string, giving prompt when appropriate */ -static char *read_string(int echo, const char *prompt) -{ - struct termios term_before, term_tmp; - char line[INPUTSIZE], *input; - struct sigaction old_sig; - int delay, nc, have_term=0; - sigset_t oset, nset; - - D(("called with echo='%s', prompt='%s'.", echo ? "ON":"OFF" , prompt)); - - input = line; - - if (isatty(STDIN_FILENO)) { /* terminal state */ - - /* is a terminal so record settings and flush it */ - if ( tcgetattr(STDIN_FILENO, &term_before) != 0 ) { - D(("<error: failed to get terminal settings>")); - return NULL; - } - memcpy(&term_tmp, &term_before, sizeof(term_tmp)); - if (!echo) { - term_tmp.c_lflag &= ~(ECHO); - } - have_term = 1; - - /* - * We make a simple attempt to block TTY signals from terminating - * the conversation without giving PAM a chance to clean up. - */ - - sigemptyset(&nset); - sigaddset(&nset, SIGINT); - sigaddset(&nset, SIGTSTP); - (void) sigprocmask(SIG_BLOCK, &nset, &oset); - - } else if (!echo) { - D(("<warning: cannot turn echo off>")); - } - - /* set up the signal handling */ - delay = get_delay(); - - /* reading the line */ - while (delay >= 0) { - - fprintf(stderr, "%s", prompt); - /* this may, or may not set echo off -- drop pending input */ - if (have_term) - (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp); - - if ( delay > 0 && set_alarm(delay, &old_sig) ) { - D(("<failed to set alarm>")); - break; - } else { - nc = read(STDIN_FILENO, line, INPUTSIZE-1); - if (have_term) { - (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); - if (!echo || expired) /* do we need a newline? */ - fprintf(stderr,"\n"); - } - if ( delay > 0 ) { - reset_alarm(&old_sig); - } - if (expired) { - delay = get_delay(); - } else if (nc > 0) { /* we got some user input */ - D(("we got some user input")); - - if (nc > 0 && line[nc-1] == '\n') { /* <NUL> terminate */ - line[--nc] = '\0'; - } else { - if (echo) { - fprintf(stderr, "\n"); - } - line[nc] = '\0'; - } - input = x_strdup(line); - _pam_overwrite(line); - - goto cleanexit; /* return malloc()ed string */ - - } else if (nc == 0) { /* Ctrl-D */ - D(("user did not want to type anything")); - - input = x_strdup(""); - if (echo) { - fprintf(stderr, "\n"); - } - goto cleanexit; /* return malloc()ed "" */ - } - } - } - - /* getting here implies that the timer expired */ - - D(("the timer appears to have expired")); - - input = NULL; - _pam_overwrite(line); - - cleanexit: - - if (have_term) { - (void) sigprocmask(SIG_SETMASK, &oset, NULL); - (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); - } - - D(("returning [%s]", input)); - - return input; -} - -/* end of read_string functions */ - -/* - * This conversation function is supposed to be a generic PAM one. - * Unfortunately, it is _not_ completely compatible with the Solaris PAM - * codebase. - * - * Namely, for msgm's that contain multiple prompts, this function - * interprets "const struct pam_message **msgm" as equivalent to - * "const struct pam_message *msgm[]". The Solaris module - * implementation interprets the **msgm object as a pointer to a - * pointer to an array of "struct pam_message" objects (that is, a - * confusing amount of pointer indirection). - */ - -int misc_conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr) -{ - int count=0; - struct pam_response *reply; - - if (num_msg <= 0) - return PAM_CONV_ERR; - - D(("allocating empty response structure array.")); - - reply = (struct pam_response *) calloc(num_msg, - sizeof(struct pam_response)); - if (reply == NULL) { - D(("no memory for responses")); - return PAM_CONV_ERR; - } - - D(("entering conversation function.")); - - for (count=0; count < num_msg; ++count) { - char *string=NULL; - - switch (msgm[count]->msg_style) { - case PAM_PROMPT_ECHO_OFF: - string = read_string(CONV_ECHO_OFF,msgm[count]->msg); - if (string == NULL) { - goto failed_conversation; - } - break; - case PAM_PROMPT_ECHO_ON: - string = read_string(CONV_ECHO_ON,msgm[count]->msg); - if (string == NULL) { - goto failed_conversation; - } - break; - case PAM_ERROR_MSG: - if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) { - goto failed_conversation; - } - break; - case PAM_TEXT_INFO: - if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) { - goto failed_conversation; - } - break; - case PAM_BINARY_PROMPT: - { - pamc_bp_t binary_prompt = NULL; - - if (!msgm[count]->msg || !pam_binary_handler_fn) { - goto failed_conversation; - } - - PAM_BP_RENEW(&binary_prompt, - PAM_BP_RCONTROL(msgm[count]->msg), - PAM_BP_LENGTH(msgm[count]->msg)); - PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg), - PAM_BP_RDATA(msgm[count]->msg)); - - if (pam_binary_handler_fn(appdata_ptr, - &binary_prompt) != PAM_SUCCESS - || (binary_prompt == NULL)) { - goto failed_conversation; - } - string = (char *) binary_prompt; - binary_prompt = NULL; - - break; - } - default: - fprintf(stderr, "erroneous conversation (%d)\n" - ,msgm[count]->msg_style); - goto failed_conversation; - } - - if (string) { /* must add to reply array */ - /* add string to list of responses */ - - reply[count].resp_retcode = 0; - reply[count].resp = string; - string = NULL; - } - } - - *response = reply; - reply = NULL; - - return PAM_SUCCESS; - -failed_conversation: - - D(("the conversation failed")); - - if (reply) { - for (count=0; count<num_msg; ++count) { - if (reply[count].resp == NULL) { - continue; - } - switch (msgm[count]->msg_style) { - case PAM_PROMPT_ECHO_ON: - case PAM_PROMPT_ECHO_OFF: - _pam_overwrite(reply[count].resp); - free(reply[count].resp); - break; - case PAM_BINARY_PROMPT: - pam_binary_handler_free(appdata_ptr, - (pamc_bp_t *) &reply[count].resp); - break; - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: - /* should not actually be able to get here... */ - free(reply[count].resp); - } - reply[count].resp = NULL; - } - /* forget reply too */ - free(reply); - reply = NULL; - } - - return PAM_CONV_ERR; -} - diff --git a/libpam_misc/xstrdup.c b/libpam_misc/xstrdup.c deleted file mode 100644 index 6a4ca6f7..00000000 --- a/libpam_misc/xstrdup.c +++ /dev/null @@ -1,31 +0,0 @@ -/* $Id$ */ - -#include <malloc.h> -#include <string.h> -#include <security/pam_misc.h> - -/* - * Safe duplication of character strings. "Paranoid"; don't leave - * evidence of old token around for later stack analysis. - */ - -char *xstrdup(const char *x) -{ - register char *new=NULL; - - if (x != NULL) { - register int i; - - for (i=0; x[i]; ++i); /* length of string */ - if ((new = malloc(++i)) == NULL) { - i = 0; - } else { - while (i-- > 0) { - new[i] = x[i]; - } - } - x = NULL; - } - - return new; /* return the duplicate or NULL on error */ -} diff --git a/libpamc/.cvsignore b/libpamc/.cvsignore deleted file mode 100644 index ce01b11d..00000000 --- a/libpamc/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -libpamc.so* -static -dynamic diff --git a/libpamc/License b/libpamc/License deleted file mode 100644 index 90106954..00000000 --- a/libpamc/License +++ /dev/null @@ -1,42 +0,0 @@ -Unless otherwise *explicitly* stated the following text describes the -licensed conditions under which the contents of this libpamc release -may be distributed: - -------------------------------------------------------------------------- -Redistribution and use in source and binary forms of libpamc, -with or without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain any existing copyright - notice, and this entire permission notice in its entirety, - including the disclaimer of warranties. - -2. Redistributions in binary form must reproduce all prior and current - copyright notices, this list of conditions, and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -3. The name of any author may not be used to endorse or promote - products derived from this software without their specific prior - written permission. - -ALTERNATIVELY, this product may be distributed under the terms of the -GNU Library General Public License (LGPL), in which case the -provisions of the GNU LGPL are required INSTEAD OF the above -restrictions. (This clause is necessary due to a potential conflict -between the GNU LGPL and the restrictions contained in a BSD-style -copyright.) - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -------------------------------------------------------------------------- - diff --git a/libpamc/Makefile b/libpamc/Makefile deleted file mode 100644 index 45d42051..00000000 --- a/libpamc/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# -# $Id$ -# - -# lots of debugging information goes to /tmp/pam-debug.log -#MOREFLAGS += -D"DEBUG" - -include ../Make.Rules - -ifeq ($(DEBUG_REL),yes) - LIBNAME=libpamcd -else - LIBNAME=libpamc -endif -VERSION=.$(MAJOR_REL) -MODIFICATION=.$(MINOR_REL) - -CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC) - -# dynamic library names - -LIBNAMED = $(LIBNAME).$(DYNTYPE) -LIBNAMEDNAME = $(LIBNAMED)$(VERSION) -LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION) - -# static library name - -LIBNAMEDSTATIC = $(LIBNAME).a - -LIBOBJECTS = pamc_client.o pamc_converse.o pamc_load.o - -ifeq ($(DYNAMIC_LIBPAM),yes) -DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS)) -endif - -ifeq ($(STATIC_LIBPAM),yes) -SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS)) -endif - -# --------------------------------------------- -## rules - -all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC) - -dirs: -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) dynamic -endif -ifeq ($(STATIC_LIBPAM),yes) - $(MKDIR) static -endif - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -$(LIBNAMED): $(DLIBOBJECTS) -ifeq ($(DYNAMIC_LIBPAM),yes) - ifeq ($(USESONAME),yes) - $(LD_L) $(SOSWITCH) $(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) - else - $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) - endif - ifeq ($(NEEDSONAME),yes) - rm -f $(LIBNAMEDFULL) - ln -s $(LIBNAMED) $(LIBNAMEDFULL) - rm -f $(LIBNAMEDNAME) - ln -s $(LIBNAMED) $(LIBNAMEDNAME) - endif -endif - -$(LIBNAMEDSTATIC): $(SLIBOBJECTS) -ifeq ($(STATIC_LIBPAM),yes) - $(AR) rc $@ $(SLIBOBJECTS) $(MODULES) - $(RANLIB) $@ -endif - -install: all - $(MKDIR) $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/security/pam_client.h $(FAKEROOT)$(INCLUDED) -ifeq ($(DYNAMIC_LIBPAM),yes) - $(MKDIR) $(FAKEROOT)$(libdir) - $(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) - $(LDCONFIG) - ifneq ($(DYNTYPE),"sl") - ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) ) - endif -endif -ifeq ($(STATIC_LIBPAM),yes) - $(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir) -endif - -remove: - rm -f $(FAKEROOT)$(INCLUDED)/pam_client.h - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED) - $(LDCONFIG) - rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC) - -clean: - rm -f a.out core *~ static/*.o dynamic/*.o - rm -f *.a *.out *.o *.so ./include/security/*~ - if [ -d dynamic ]; then rmdir dynamic ; fi - if [ -d static ]; then rmdir static ; fi - diff --git a/libpamc/include/security/pam_client.h b/libpamc/include/security/pam_client.h deleted file mode 100644 index 2afddd77..00000000 --- a/libpamc/include/security/pam_client.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org> - * - * This header file provides the prototypes for the PAM client API - */ - -#ifndef PAM_CLIENT_H -#define PAM_CLIENT_H - -#ifdef __cplusplus -extern "C" { -#endif /* def __cplusplus */ - -#include <unistd.h> -#include <string.h> -#include <stdio.h> - -/* opaque agent handling structure */ - -typedef struct pamc_handle_s *pamc_handle_t; - -/* binary prompt structure pointer */ -#ifndef __u32 -# define __u32 unsigned int -#endif -#ifndef __u8 -# define __u8 unsigned char -#endif -typedef struct { __u32 length; __u8 control; } *pamc_bp_t; - -/* - * functions provided by libpamc - */ - -/* - * Initialize the agent abstraction library - */ - -pamc_handle_t pamc_start(void); - -/* - * Terminate the authentication process - */ - -int pamc_end(pamc_handle_t *pch); - -/* - * force the loading of a specified agent - */ - -int pamc_load(pamc_handle_t pch, const char *agent_id); - -/* - * Single conversation interface for binary prompts - */ - -int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p); - -/* - * disable an agent - */ - -int pamc_disable(pamc_handle_t pch, const char *agent_id); - -/* - * obtain a list of available agents - */ - -char **pamc_list_agents(pamc_handle_t pch); - -/* - * PAM_BP_ MACROS for creating, destroying and manipulating binary prompts - */ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#ifndef PAM_BP_ASSERT -# define PAM_BP_ASSERT(x) do { printf(__FILE__ "(%d): %s\n", \ - __LINE__, x) ; exit(1); } while (0) -#endif /* PAM_BP_ASSERT */ - -#ifndef PAM_BP_CALLOC -# define PAM_BP_CALLOC calloc -#endif /* PAM_BP_CALLOC */ - -#ifndef PAM_BP_FREE -# define PAM_BP_FREE free -#endif /* PAM_BP_FREE */ - -#define __PAM_BP_WOCTET(x,y) (*((y) + (__u8 *)(x))) -#define __PAM_BP_ROCTET(x,y) (*((y) + (const __u8 *)(x))) - -#define PAM_BP_MIN_SIZE (sizeof(__u32) + sizeof(__u8)) -#define PAM_BP_MAX_LENGTH 0x20000 /* an advisory limit */ -#define PAM_BP_WCONTROL(x) (__PAM_BP_WOCTET(x,4)) -#define PAM_BP_RCONTROL(x) (__PAM_BP_ROCTET(x,4)) -#define PAM_BP_SIZE(x) ((__PAM_BP_ROCTET(x,0)<<24)+ \ - (__PAM_BP_ROCTET(x,1)<<16)+ \ - (__PAM_BP_ROCTET(x,2)<< 8)+ \ - (__PAM_BP_ROCTET(x,3) )) -#define PAM_BP_LENGTH(x) (PAM_BP_SIZE(x) - PAM_BP_MIN_SIZE) -#define PAM_BP_WDATA(x) (PAM_BP_MIN_SIZE + (__u8 *) (x)) -#define PAM_BP_RDATA(x) (PAM_BP_MIN_SIZE + (const __u8 *) (x)) - -/* Note, this macro always '\0' terminates renewed packets */ - -#define PAM_BP_RENEW(old_p, cntrl, data_length) \ -do { \ - if (old_p) { \ - if (*(old_p)) { \ - __u32 __size; \ - __size = PAM_BP_SIZE(*(old_p)); \ - memset(*(old_p), 0, __size); \ - PAM_BP_FREE(*(old_p)); \ - } \ - if (cntrl) { \ - __u32 __size; \ - \ - __size = PAM_BP_MIN_SIZE + data_length; \ - if ((*(old_p) = PAM_BP_CALLOC(1, 1+__size))) { \ - __PAM_BP_WOCTET(*(old_p), 3) = __size & 0xFF; \ - __PAM_BP_WOCTET(*(old_p), 2) = (__size>>=8) & 0xFF; \ - __PAM_BP_WOCTET(*(old_p), 1) = (__size>>=8) & 0xFF; \ - __PAM_BP_WOCTET(*(old_p), 0) = (__size>>=8) & 0xFF; \ - (*(old_p))->control = cntrl; \ - } else { \ - PAM_BP_ASSERT("out of memory for binary prompt"); \ - } \ - } else { \ - *old_p = NULL; \ - } \ - } else { \ - PAM_BP_ASSERT("programming error, invalid binary prompt pointer"); \ - } \ -} while (0) - -#define PAM_BP_FILL(prmpt, offset, length, data) \ -do { \ - size_t bp_length; \ - __u8 *prompt = (__u8 *) (prmpt); \ - bp_length = PAM_BP_LENGTH(prompt); \ - if (bp_length < ((length)+(offset))) { \ - PAM_BP_ASSERT("attempt to write over end of prompt"); \ - } \ - memcpy((offset) + PAM_BP_WDATA(prompt), (data), (length)); \ -} while (0) - -#define PAM_BP_EXTRACT(prmpt, offset, length, data) \ -do { \ - size_t __bp_length; \ - const __u8 *__prompt = (const __u8 *) (prmpt); \ - __bp_length = PAM_BP_LENGTH(__prompt); \ - if (((offset) < 0) || (__bp_length < ((length)+(offset))) \ - || ((length) < 0)) { \ - PAM_BP_ASSERT("invalid extraction from prompt"); \ - } \ - memcpy((data), (offset) + PAM_BP_RDATA(__prompt), (length)); \ -} while (0) - - -/* Control types */ - -#define PAM_BPC_FALSE 0 -#define PAM_BPC_TRUE 1 - -#define PAM_BPC_OK 0x01 /* continuation packet */ -#define PAM_BPC_SELECT 0x02 /* initialization packet */ -#define PAM_BPC_DONE 0x03 /* termination packet */ -#define PAM_BPC_FAIL 0x04 /* unable to execute */ - -/* The following control characters are only legal for echanges - between an agent and a client (it is the responsibility of the - client to enforce this rule in the face of a rogue server): */ - -#define PAM_BPC_GETENV 0x41 /* obtain client env.var */ -#define PAM_BPC_PUTENV 0x42 /* set client env.var */ -#define PAM_BPC_TEXT 0x43 /* display message */ -#define PAM_BPC_ERROR 0x44 /* display error message */ -#define PAM_BPC_PROMPT 0x45 /* echo'd text prompt */ -#define PAM_BPC_PASS 0x46 /* non-echo'd text prompt*/ - -/* quick check for prompts that are legal for the client (by - implication the server too) to send to libpamc */ - -#define PAM_BPC_FOR_CLIENT(/* pamc_bp_t */ prompt) \ - (((prompt)->control <= PAM_BPC_FAIL && (prompt)->control >= PAM_BPC_OK) \ - ? PAM_BPC_TRUE:PAM_BPC_FALSE) - -#ifdef __cplusplus -} -#endif /* def __cplusplus */ - -#endif /* PAM_CLIENT_H */ diff --git a/libpamc/libpamc.h b/libpamc/libpamc.h deleted file mode 100644 index 93c833c6..00000000 --- a/libpamc/libpamc.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> - * - */ - -#ifndef LIBPAMC_H -#define LIBPAMC_H - -#include <security/pam_client.h> -#include <security/_pam_macros.h> - -#include <sys/stat.h> -#include <unistd.h> -#include <sys/types.h> -#include <dirent.h> -#include <sys/wait.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> - -#define _PAMC_DEFAULT_TOP_FD 10 - -struct pamc_handle_s { - struct pamc_agent_s *current; - struct pamc_agent_s *chain; - struct pamc_blocked_s *blocked_agents; - int max_path; - char **agent_paths; - int combined_status; - int highest_fd_to_close; -}; - -typedef struct pamc_blocked_s { - char *id; /* <NUL> terminated */ - struct pamc_blocked_s *next; -} pamc_blocked_t; - -typedef struct pamc_agent_s { - char *id; - int id_length; - struct pamc_agent_s *next; - int writer; /* write to agent */ - int reader; /* read from agent */ - pid_t pid; /* agent process id */ -} pamc_agent_t; - -/* used to build a tree of unique, sorted agent ids */ - -typedef struct pamc_id_node { - struct pamc_id_node *left, *right; - int child_count; - char *agent_id; -} pamc_id_node_t; - -/* internal function */ -int __pamc_valid_agent_id(int id_length, const char *id); - -#define PAMC_SYSTEM_AGENT_PATH "/lib/pamc:/usr/lib/pamc" -#define PAMC_SYSTEM_AGENT_SEPARATOR ':' - -#endif /* LIBPAMC_H */ diff --git a/libpamc/pamc_client.c b/libpamc/pamc_client.c deleted file mode 100644 index 9d2bc671..00000000 --- a/libpamc/pamc_client.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> - * - * pamc_start and pamc_end - */ - -#include "libpamc.h" - -/* - * liberate path list - */ - -static void __pamc_delete_path_list(pamc_handle_t pch) -{ - int i; - - for (i=0; pch->agent_paths[i]; ++i) { - free(pch->agent_paths[i]); - pch->agent_paths[i] = NULL; - } - - free(pch->agent_paths); - pch->agent_paths = NULL; -} - -/* - * open the pamc library - */ - -pamc_handle_t pamc_start(void) -{ - int i, count, last, this; - const char *default_path; - pamc_handle_t pch; - - pch = calloc(1, sizeof(struct pamc_handle_s)); - if (pch == NULL) { - D(("no memory for *pch")); - return NULL; - } - - pch->highest_fd_to_close = _PAMC_DEFAULT_TOP_FD; - - default_path = getenv("PAMC_AGENT_PATH"); - if (default_path == NULL) { - default_path = PAMC_SYSTEM_AGENT_PATH; - } - - /* number of individual paths */ - for (count=1, i=0; default_path[i]; ++i) { - if (default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR) { - ++count; - } - } - - pch->agent_paths = calloc(count+1, sizeof(char *)); - if (pch->agent_paths == NULL) { - D(("no memory for path list")); - goto drop_pch; - } - - this = last = i = 0; - while ( default_path[i] || (i != last) ) { - if ( default_path[i] == PAMC_SYSTEM_AGENT_SEPARATOR - || !default_path[i] ) { - int length; - - pch->agent_paths[this] = malloc(length = 1+i-last); - - if (pch->agent_paths[this] == NULL) { - D(("no memory for next path")); - goto drop_list; - } - - memcpy(pch->agent_paths[this], default_path + last, i-last); - pch->agent_paths[this][i-last] = '\0'; - if (length > pch->max_path) { - pch->max_path = length; - } - - if (++this == count) { - break; - } - - last = ++i; - } else { - ++i; - } - } - - return pch; - -drop_list: - __pamc_delete_path_list(pch); - -drop_pch: - free(pch); - - return NULL; -} - -/* - * shutdown each of the loaded agents and - */ - -static int __pamc_shutdown_agents(pamc_handle_t pch) -{ - int retval = PAM_BPC_TRUE; - - D(("called")); - - while (pch->chain) { - pid_t pid; - int status; - pamc_agent_t *this; - - this = pch->chain; - D(("cleaning up agent %p", this)); - pch->chain = pch->chain->next; - this->next = NULL; - D(("cleaning up agent: %s", this->id)); - - /* close off contact with agent and wait for it to shutdown */ - - close(this->writer); - this->writer = -1; - close(this->reader); - this->reader = -1; - - pid = waitpid(this->pid, &status, 0); - if (pid == this->pid) { - - D(("is exit:%d, exit val:%d", - WIFEXITED(status), WEXITSTATUS(status))); - - if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) { - retval = PAM_BPC_FALSE; - } - } else { - D(("problem shutting down agent (%s): pid(%d) != waitpid(%d)!?", - this->id, this->pid, pid)); - retval = PAM_BPC_FALSE; - } - pid = this->pid = 0; - - memset(this->id, 0, this->id_length); - free(this->id); - this->id = NULL; - this->id_length = 0; - - free(this); - this = NULL; - } - - return retval; -} - -/* - * close the pamc library - */ - -int pamc_end(pamc_handle_t *pch_p) -{ - int retval; - - if (pch_p == NULL) { - D(("called with no pch_p")); - return PAM_BPC_FALSE; - } - - if (*pch_p == NULL) { - D(("called with no *pch_p")); - return PAM_BPC_FALSE; - } - - D(("removing path_list")); - __pamc_delete_path_list(*pch_p); - - D(("shutting down agents")); - retval = __pamc_shutdown_agents(*pch_p); - - D(("freeing *pch_p")); - free(*pch_p); - *pch_p = NULL; - - return retval; -} diff --git a/libpamc/pamc_converse.c b/libpamc/pamc_converse.c deleted file mode 100644 index 540a7d86..00000000 --- a/libpamc/pamc_converse.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org> - * - * pamc_converse - */ - -#include "libpamc.h" - -/* - * select agent - */ - -static int __pamc_select_agent(pamc_handle_t pch, char *agent_id) -{ - pamc_agent_t *agent; - - for (agent = pch->chain; agent; agent = agent->next) { - if (!strcmp(agent->id, agent_id)) { - pch->current = agent; - return PAM_BPC_TRUE; - } - } - - D(("failed to locate agent")); - pch->current = NULL; - return PAM_BPC_FALSE; -} - -/* - * pass a binary prompt to the active agent and wait for a reply prompt - */ - -int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p) -{ - __u32 size, offset=0; - __u8 control, raw[PAM_BP_MIN_SIZE]; - - D(("called")); - - if (pch == NULL) { - D(("null pch")); - goto pamc_converse_failure; - } - - if (prompt_p == NULL) { - D(("null prompt_p")); - goto pamc_converse_failure; - } - - if (*prompt_p == NULL) { - D(("null *prompt_p")); - goto pamc_converse_failure; - } - - /* from here on, failures are interoperability problems.. */ - - size = PAM_BP_SIZE(*prompt_p); - if (size < PAM_BP_MIN_SIZE) { - D(("problem with size being too short (%u)", size)); - goto pamc_unknown_prompt; - } - - if (PAM_BPC_FOR_CLIENT(*prompt_p) != PAM_BPC_TRUE) { - D(("*prompt_p is not legal for the client to use")); - goto pamc_unknown_prompt; - } - - /* do we need to select the agent? */ - if ((*prompt_p)->control == PAM_BPC_SELECT) { - char *rawh; - int i, retval; - - D(("selecting a specified agent")); - - rawh = (char *) *prompt_p; - for (i = PAM_BP_MIN_SIZE; i<size; ++i) { - if (rawh[i] == '/') { - break; - } - } - - if ( (i >= size) - || !__pamc_valid_agent_id(i-PAM_BP_MIN_SIZE, - rawh + PAM_BP_MIN_SIZE) ) { - goto pamc_unknown_prompt; - } - - rawh[i] = '\0'; - retval = pamc_load(pch, PAM_BP_MIN_SIZE + rawh); - if (retval == PAM_BPC_TRUE) { - retval = __pamc_select_agent(pch, PAM_BP_MIN_SIZE + rawh); - } - rawh[i] = '/'; - - if (retval != PAM_BPC_TRUE) { - goto pamc_unknown_prompt; - } - - D(("agent is loaded")); - } - - if (pch->current == NULL) { - D(("unable to address agent")); - goto pamc_unknown_prompt; - } - - /* pump all of the prompt into the agent */ - do { - int rval = write(pch->current->writer, - offset + (const __u8 *) (*prompt_p), - size - offset); - if (rval == -1) { - switch (errno) { - case EINTR: - break; - default: - D(("problem writing to agent: %s", strerror(errno))); - goto pamc_unknown_prompt; - } - } else { - offset += rval; - } - } while (offset < size); - - D(("whole prompt sent to agent")); - - /* read size and control for response prompt */ - - offset = 0; - memset(raw, 0, sizeof(raw)); - do { - int rval; - - rval = read(pch->current->reader, raw + offset, - PAM_BP_MIN_SIZE - offset); - - if (rval == -1) { - switch (errno) { - case EINTR: - break; - default: - D(("problem reading from agent: %s", strerror(errno))); - goto pamc_unknown_prompt; - } - } else if (rval) { - offset += rval; - } else { - D(("agent has closed its output pipe - nothing more to read")); - goto pamc_converse_failure; - } - } while (offset < PAM_BP_MIN_SIZE); - - /* construct the whole reply prompt */ - - size = PAM_BP_SIZE(raw); - control = PAM_BP_RCONTROL(raw); - memset(raw, 0, sizeof(raw)); - - D(("agent replied with prompt of size %d and control %u", - size, control)); - - PAM_BP_RENEW(prompt_p, control, size - PAM_BP_MIN_SIZE); - if (*prompt_p == NULL) { - D(("problem making a new prompt for reply")); - goto pamc_unknown_prompt; - } - - /* read the rest of the reply prompt -- note offset has the correct - value from the previous loop */ - - while (offset < size) { - int rval = read(pch->current->reader, offset + (__u8 *) *prompt_p, - size-offset); - - if (rval == -1) { - switch (errno) { - case EINTR: - break; - default: - D(("problem reading from agent: %s", strerror(errno))); - goto pamc_unknown_prompt; - } - } else if (rval) { - offset += rval; - } else { - D(("problem reading prompt (%d) with %d to go", - size, size-offset)); - goto pamc_converse_failure; - } - } - - D(("returning success")); - - return PAM_BPC_TRUE; - -pamc_converse_failure: - - D(("conversation failure")); - PAM_BP_RENEW(prompt_p, 0, 0); - return PAM_BPC_FALSE; - -pamc_unknown_prompt: - - /* the server is trying something that the client does not support */ - D(("unknown prompt")); - PAM_BP_RENEW(prompt_p, PAM_BPC_FAIL, 0); - return PAM_BPC_TRUE; -} - diff --git a/libpamc/pamc_load.c b/libpamc/pamc_load.c deleted file mode 100644 index b3c0b5d5..00000000 --- a/libpamc/pamc_load.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) 1999 Andrew G. Morgan <morgan@ftp.kernel.org> - * - * pamc_load - */ - -#include "libpamc.h" - -static int __pamc_exec_agent(pamc_handle_t pch, pamc_agent_t *agent) -{ - char *full_path; - int found_agent, length, reset_length, to_agent[2], from_agent[2]; - int return_code = PAM_BPC_FAIL; - - if (agent->id[agent->id_length] != '\0') { - PAM_BP_ASSERT("libpamc: internal error agent_id not terminated"); - } - - for (length=0; (length < agent->id_length); ++length) { - switch (agent->id[length]) { - case '/': - D(("ill formed agent id")); - return PAM_BPC_FAIL; - } - } - - /* enough memory for any path + this agent */ - reset_length = 3 + pch->max_path + agent->id_length; - D(("reset_length = %d (3+%d+%d)", - reset_length, pch->max_path, agent->id_length)); - full_path = malloc(reset_length); - if (full_path == NULL) { - D(("no memory for agent path")); - return PAM_BPC_FAIL; - } - - found_agent = 0; - for (length=0; pch->agent_paths[length]; ++length) { - struct stat buf; - - D(("path: [%s]", pch->agent_paths[length])); - D(("agent id: [%s]", agent->id)); - - sprintf(full_path, "%s/%s", pch->agent_paths[length], agent->id); - - D(("looking for agent here: [%s]\n", full_path)); - if (stat(full_path, &buf) == 0) { - D(("file existis")); - found_agent = 1; - break; - } - } - - if (! found_agent) { - D(("no agent was found")); - goto free_and_return; - } - - if (pipe(to_agent)) { - D(("failed to open pipe to agent")); - goto free_and_return; - } - - if (pipe(from_agent)) { - D(("failed to open pipe from agent")); - goto close_the_agent; - } - - agent->pid = fork(); - if (agent->pid == -1) { - - D(("failed to fork for agent")); - goto close_both_pipes; - - } else if (agent->pid == 0) { - - int i; - - dup2(from_agent[1], STDOUT_FILENO); - dup2(to_agent[0], STDIN_FILENO); - - /* we close all of the files that have filedescriptors lower - and equal to twice the highest we have seen, The idea is - that we don't want to leak filedescriptors to agents from a - privileged client application. - - XXX - this is a heuristic at this point. There is a growing - need for an extra 'set param' libpamc function, that could - be used to supply info like the highest fd to close etc.. - */ - - if (from_agent[1] > pch->highest_fd_to_close) { - pch->highest_fd_to_close = 2*from_agent[1]; - } - - for (i=0; i <= pch->highest_fd_to_close; ++i) { - switch (i) { - case STDOUT_FILENO: - case STDERR_FILENO: - case STDIN_FILENO: - /* only these three remain open */ - break; - default: - (void) close(i); /* don't care if its not open */ - } - } - - /* we make no attempt to drop other privileges - this library - has no idea how that would be done in the general case. It - is up to the client application (when calling - pamc_converse) to make sure no privilege will leak into an - (untrusted) agent. */ - - /* we propogate no environment - future versions of this - library may have the ability to audit all agent - transactions. */ - - D(("exec'ing agent %s", full_path)); - execle(full_path, "pam-agent", NULL, NULL); - - D(("exec failed")); - exit(1); - - } - - close(to_agent[0]); - close(from_agent[1]); - - agent->writer = to_agent[1]; - agent->reader = from_agent[0]; - - return_code = PAM_BPC_TRUE; - goto free_and_return; - -close_both_pipes: - close(from_agent[0]); - close(from_agent[1]); - -close_the_agent: - close(to_agent[0]); - close(to_agent[1]); - -free_and_return: - memset(full_path, 0, reset_length); - free(full_path); - - D(("returning %d", return_code)); - - return return_code; -} - -/* - * has the named agent been loaded? - */ - -static int __pamc_agent_is_enabled(pamc_handle_t pch, const char *agent_id) -{ - pamc_agent_t *agent; - - for (agent = pch->chain; agent; agent = agent->next) { - if (!strcmp(agent->id, agent_id)) { - D(("agent already loaded")); - return PAM_BPC_TRUE; - } - } - - D(("agent is not loaded")); - return PAM_BPC_FALSE; -} - -/* - * has the named agent been disabled? - */ - -static int __pamc_agent_is_disabled(pamc_handle_t pch, const char *agent_id) -{ - pamc_blocked_t *blocked; - - for (blocked=pch->blocked_agents; blocked; blocked = blocked->next) { - if (!strcmp(agent_id, blocked->id)) { - D(("agent is disabled")); - return PAM_BPC_TRUE; - } - } - - D(("agent is not disabled")); - return PAM_BPC_FALSE; -} - -/* - * disable an agent - */ - -int pamc_disable(pamc_handle_t pch, const char *agent_id) -{ - pamc_blocked_t *block; - - if (pch == NULL) { - D(("pch is NULL")); - return PAM_BPC_FALSE; - } - - if (agent_id == NULL) { - D(("agent_id is NULL")); - return PAM_BPC_FALSE; - } - - if (__pamc_agent_is_enabled(pch, agent_id) != PAM_BPC_FALSE) { - D(("agent is already loaded")); - return PAM_BPC_FALSE; - } - - if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) { - D(("agent is already disabled")); - return PAM_BPC_TRUE; - } - - block = calloc(1, sizeof(pamc_blocked_t)); - if (block == NULL) { - D(("no memory for new blocking structure")); - return PAM_BPC_FALSE; - } - - block->id = malloc(1 + strlen(agent_id)); - if (block->id == NULL) { - D(("no memory for agent id")); - free(block); - return PAM_BPC_FALSE; - } - - strcpy(block->id, agent_id); - block->next = pch->blocked_agents; - pch->blocked_agents = block; - - return PAM_BPC_TRUE; -} - -/* - * force the loading of a particular agent - */ - -int pamc_load(pamc_handle_t pch, const char *agent_id) -{ - pamc_agent_t *agent; - int length; - - /* santity checking */ - - if (pch == NULL) { - D(("pch is NULL")); - return PAM_BPC_FALSE; - } - - if (agent_id == NULL) { - D(("agent_id is NULL")); - return PAM_BPC_FALSE; - } - - if (__pamc_agent_is_disabled(pch, agent_id) != PAM_BPC_FALSE) { - D(("sorry agent is disabled")); - return PAM_BPC_FALSE; - } - - length = strlen(agent_id); - - /* scan list to see if agent is loaded */ - - if (__pamc_agent_is_enabled(pch, agent_id) == PAM_BPC_TRUE) { - D(("no need to load an already loaded agent (%s)", agent_id)); - return PAM_BPC_TRUE; - } - - /* not in the list, so we need to load it and add it to the head - of the chain */ - - agent = calloc(1, sizeof(pamc_agent_t)); - if (agent == NULL) { - D(("no memory for new agent")); - return PAM_BPC_FALSE; - } - agent->id = calloc(1, 1+length); - if (agent->id == NULL) { - D(("no memory for new agent's id")); - goto fail_free_agent; - } - memcpy(agent->id, agent_id, length); - agent->id[length] = '\0'; - agent->id_length = length; - - if (__pamc_exec_agent(pch, agent) != PAM_BPC_TRUE) { - D(("unable to exec agent")); - goto fail_free_agent_id; - } - - agent->next = pch->chain; - pch->chain = agent; - - return PAM_BPC_TRUE; - -fail_free_agent_id: - - memset(agent->id, 0, agent->id_length); - free(agent->id); - - memset(agent, 0, sizeof(*agent)); - -fail_free_agent: - - free(agent); - return PAM_BPC_FALSE; -} - -/* - * what's a valid agent name? - */ - -int __pamc_valid_agent_id(int id_length, const char *id) -{ - int post, i; - - for (i=post=0 ; i < id_length; ++i) { - int ch = id[i++]; - - if (isalpha(ch) || isdigit(ch) || (ch == '_')) { - continue; - } else if (post && (ch == '.')) { - continue; - } else if ((i > 1) && (!post) && (ch == '@')) { - post = 1; - } else { - D(("id=%s contains '%c' which is illegal", id, ch)); - return 0; - } - } - - if (!i) { - D(("length of id is 0")); - return 0; - } else { - return 1; /* id is valid */ - } -} - -/* - * building a tree of available agent names - */ - -static pamc_id_node_t *__pamc_add_node(pamc_id_node_t *root, const char *id, - int *counter) -{ - if (root) { - - int cmp; - - if ((cmp = strcmp(id, root->agent_id))) { - if (cmp > 0) { - root->right = __pamc_add_node(root->right, id, - &(root->child_count)); - } else { - root->left = __pamc_add_node(root->left, id, - &(root->child_count)); - } - } - - return root; - - } else { - - pamc_id_node_t *node = calloc(1, sizeof(pamc_id_node_t)); - - if (node) { - node->agent_id = malloc(1+strlen(id)); - if (node->agent_id) { - strcpy(node->agent_id, id); - } else { - free(node); - node = NULL; - } - } - - (*counter)++; - return node; - } -} - -/* - * drop all of the tree and any remaining ids - */ - -static pamc_id_node_t *__pamc_liberate_nodes(pamc_id_node_t *tree) -{ - if (tree) { - if (tree->agent_id) { - free(tree->agent_id); - tree->agent_id = NULL; - } - - tree->left = __pamc_liberate_nodes(tree->left); - tree->right = __pamc_liberate_nodes(tree->right); - - tree->child_count = 0; - free(tree); - } - - return NULL; -} - -/* - * fill a list with the contents of the tree (in ascii order) - */ - -static void __pamc_fill_list_from_tree(pamc_id_node_t *tree, char **agent_list, - int *counter) -{ - if (tree) { - __pamc_fill_list_from_tree(tree->left, agent_list, counter); - agent_list[(*counter)++] = tree->agent_id; - tree->agent_id = NULL; - __pamc_fill_list_from_tree(tree->right, agent_list, counter); - } -} - -/* - * get a list of the available agents - */ - -char **pamc_list_agents(pamc_handle_t pch) -{ - int i, total_agent_count=0; - pamc_id_node_t *tree = NULL; - char **agent_list; - - /* loop over agent paths */ - - for (i=0; pch->agent_paths[i]; ++i) { - DIR *dir; - - dir = opendir(pch->agent_paths[i]); - if (dir) { - struct dirent *item; - - while ((item = readdir(dir))) { - - /* this is a cheat on recognizing agent_ids */ - if (!__pamc_valid_agent_id(strlen(item->d_name), - item->d_name)) { - continue; - } - - tree = __pamc_add_node(tree, item->d_name, &total_agent_count); - } - - closedir(dir); - } - } - - /* now, we build a list of ids */ - D(("total of %d available agents\n", total_agent_count)); - - agent_list = calloc(total_agent_count+1, sizeof(char *)); - if (agent_list) { - int counter=0; - - __pamc_fill_list_from_tree(tree, agent_list, &counter); - if (counter != total_agent_count) { - PAM_BP_ASSERT("libpamc: internal error transcribing tree"); - } - } else { - D(("no memory for agent list")); - } - - __pamc_liberate_nodes(tree); - - return agent_list; -} diff --git a/libpamc/test/agents/secret@here b/libpamc/test/agents/secret@here deleted file mode 100755 index afdcbaa8..00000000 --- a/libpamc/test/agents/secret@here +++ /dev/null @@ -1,308 +0,0 @@ -#!/usr/bin/perl -# -# This is a simple example PAM authentication agent, it implements a -# simple shared secret authentication scheme. The PAM module pam_secret.so -# is its counter part. Both the agent and the remote server are able to -# authenticate one another, but the server is given the opportunity to -# ignore a failed authentication. -# - -$^W = 1; -use strict; -use IPC::Open2; -$| = 1; - -# display extra information to STDERR -my $debug = 0; -if (scalar @ARGV) { - $debug = 1; -} - -# Globals - -my %state; -my $default_key; - -my $next_key = $$; - -# loop over binary prompts -for (;;) { - my ($control, $data) = ReadBinaryPrompt(); - my ($reply_control, $reply_data); - - if ($control == 0) { - if ($debug) { - print STDERR "agent: no packet to read\n"; - } - last; - } elsif ($control == 0x02) { - ($reply_control, $reply_data) = HandleAgentSelection($data); - } elsif ($control == 0x01) { - ($reply_control, $reply_data) = HandleContinuation($data); - } else { - if ($debug) { - print STDERR - "agent: unrecognized packet $control {$data} to read\n"; - } - ($reply_control, $reply_data) = (0x04, ""); - } - - WriteBinaryPrompt($reply_control, $reply_data); -} - -# Only willing to exit well if we've completed our authentication exchange - -if (scalar keys %state) { - if ($debug) { - print STDERR "The following sessions are still active:\n "; - print STDERR join ', ', keys %state; - print STDERR "\n"; - } - exit 1; -} else { - exit 0; -} - -sub HandleAgentSelection ($) { - my ($data) = @_; - - unless ( $data =~ /^([a-zA-Z0-9_]+\@?[a-zA-Z0-9_.]*)\/(.*)$/ ) { - return (0x04, ""); - } - - my ($agent_name, $payload) = ($1, $2); - if ($debug) { - print STDERR "agent: ". "agent=$agent_name, payload=$payload\n"; - } - - # this agent has a defined name - if ($agent_name ne "secret\@here") { - if ($debug) { - print STDERR "bad agent name: [$agent_name]\n"; - } - return (0x04, ""); - } - - # the selection request is acompanied with a hexadecimal cookie - my @tokens = split '\|', $payload; - - unless ((scalar @tokens) == 2) { - if ($debug) { - print STDERR "bad payload\n"; - } - return (0x04, ""); - } - - unless ($tokens[1] =~ /^[a-z0-9]+$/) { - if ($debug) { - print STDERR "bad server cookie\n"; - } - return (0x04, ""); - } - - my $shared_secret = IdentifyLocalSecret($tokens[0]); - - unless (defined $shared_secret) { - # make a secret up - if ($debug) { - print STDERR "agent: cannot authenticate user\n"; - } - $shared_secret = GetRandom(); - } - - my $local_cookie = GetRandom(); - $default_key = $next_key++; - - $state{$default_key} = $local_cookie ."|". $tokens[1] ."|". $shared_secret; - - if ($debug) { - print STDERR "agent: \$state{$default_key} = $state{$default_key}\n"; - } - - return (0x01, $default_key ."|". $local_cookie); -} - -sub HandleContinuation ($) { - my ($data) = @_; - - my ($key, $server_digest) = split '\|', $data; - - unless (defined $state{$key}) { - # retries and out of sequence prompts are not permitted - return (0x04, ""); - } - - my $expected_digest = CreateDigest($state{$key}); - my ($local_cookie, $remote_cookie, $shared_secret) - = split '\|', $state{$key}; - delete $state{$key}; - - unless ($expected_digest eq $server_digest) { - if ($debug) { - print STDERR "agent: don't trust server - faking reply\n"; - print STDERR "agent: got ($server_digest)\n"; - print STDERR "agent: expected ($expected_digest)\n"; - } - - ## FIXME: Agent should exchange a prompt with the client warning - ## that the server is faking us out. - - return (0x03, CreateDigest($expected_digest . $data . GetRandom())); - } - - if ($debug) { - print STDERR "agent: server appears to know the secret\n"; - } - - my $session_authenticated_ticket = - CreateDigest($remote_cookie."|".$shared_secret."|".$local_cookie); - - # FIXME: Agent should set a derived session key environment - # variable (available for the client (and its children) to sign - # future data exchanges. - - if ($debug) { - print STDERR "agent: should putenv(" - ."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n"; - } - - # return agent's authenticating digest - return (0x03, CreateDigest($shared_secret."|".$remote_cookie - ."|".$local_cookie)); -} - -sub ReadBinaryPrompt { - my $buffer = " "; - my $count = read(STDIN, $buffer, 5); - if ($count == 0) { - # no more packets to read - return (0, ""); - } - - if ($count != 5) { - # broken packet header - return (-1, ""); - } - - my ($length, $control) = unpack("N C", $buffer); - if ($length < 5) { - # broken packet length - return (-1, ""); - } - - my $data = ""; - $length -= 5; - while ($count = read(STDIN, $buffer, $length)) { - $data .= $buffer; - if ($count != $length) { - $length -= $count; - next; - } - - if ($debug) { - print STDERR "agent: ". "data is [$data]\n"; - } - - return ($control, $data); - } - - # broken packet data - return (-1, ""); -} - -sub WriteBinaryPrompt ($$) { - my ($control, $data) = @_; - - my $length = 5 + length($data); - if ($debug) { - printf STDERR "agent: ". "{%d|0x%.2x|%s}\n", $length, $control, $data; - } - my $bp = pack("N C a*", $length, $control, $data); - print STDOUT $bp; - if ($debug) { - printf STDERR "agent: ". "agent has replied\n"; - } -} - -## -## Here is where we parse the simple secret file -## The format of this file is a list of lines of the following form: -## -## user@client0.host.name secret_string1 -## user@client1.host.name secret_string2 -## user@client2.host.name secret_string3 -## - -sub IdentifyLocalSecret ($) { - my ($identifier) = @_; - my $secret; - - if (open SECRETS, "< ". (getpwuid($<))[7] ."/.secret\@here") { - my $line; - while (defined ($line = <SECRETS>)) { - my ($id, $sec) = split /[\s]+/, $line; - if ((defined $id) && ($id eq $identifier)) { - $secret = $sec; - last; - } - } - close SECRETS; - } - - return $secret; -} - -## Here is where we generate a message digest - -sub CreateDigest ($) { - my ($data) = @_; - - my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -") - or die "you'll need /usr/bin/md5sum installed"; - - my $oldfd = select MD5in; $|=1; select $oldfd; - if ($debug) { - print STDERR "agent: ". "telling md5: <$data>\n"; - } - print MD5in "$data"; - close MD5in; - my $reply = <MD5out>; - ($reply) = split /\s/, $reply; - if ($debug) { - print STDERR "agent: ". "md5 said: <$reply>\n"; - } - close MD5out; - - return $reply; -} - -## get a random number - -sub GetRandom { - - if ( -r "/dev/urandom" ) { - open RANDOM, "< /dev/urandom" or die "crazy"; - - my $i; - my $reply = ""; - - for ($i=0; $i<4; ++$i) { - my $buffer = " "; - while (read(RANDOM, $buffer, 4) != 4) { - ; - } - $reply .= sprintf "%.8x", unpack("N", $buffer); - if ($debug) { - print STDERR "growing reply: [$reply]\n"; - } - } - close RANDOM; - - return $reply; - } else { - print STDERR "agent: ". "[got linux?]\n"; - return "%.8x%.8x%.8x%.8x", time, time, time, time; - } - -} - diff --git a/libpamc/test/modules/Makefile b/libpamc/test/modules/Makefile deleted file mode 100644 index 48065462..00000000 --- a/libpamc/test/modules/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -CFLAGS = -g -fPIC -I"../../include" - -pam_secret.so: pam_secret.o - ld -x --shared -o pam_secret.so pam_secret.o -lc - -.o.c: - -clean: - rm -f *.so *.o diff --git a/libpamc/test/modules/pam_secret.c b/libpamc/test/modules/pam_secret.c deleted file mode 100644 index 7efa8c23..00000000 --- a/libpamc/test/modules/pam_secret.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * $Id$ - * - * Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org> - */ - -/* - * WARNING: AS WRITTEN THIS CODE IS NOT SECURE. THE MD5 IMPLEMENTATION - * NEEDS TO BE INTEGRATED MORE NATIVELY. - */ - -/* #define DEBUG */ - -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <security/pam_modules.h> -#include <security/pam_client.h> -#include <security/_pam_macros.h> - -/* - * This is a sample module that demonstrates the use of binary prompts - * and how they can be used to implement sophisticated authentication - * schemes. - */ - -struct ps_state_s { - int retval; /* last retval returned by the authentication fn */ - int state; /* what state the module was in when it - returned incomplete */ - - char *username; /* the name of the local user */ - - char server_cookie[33]; /* storage for 32 bytes of server cookie */ - char client_cookie[33]; /* storage for 32 bytes of client cookie */ - - char *secret_data; /* pointer to <NUL> terminated secret_data */ - int invalid_secret; /* indication of whether the secret is valid */ - - pamc_bp_t current_prompt; /* place to store the current prompt */ - pamc_bp_t current_reply; /* place to receive the reply prompt */ -}; - -#define PS_STATE_ID "PAM_SECRET__STATE" -#define PS_AGENT_ID "secret@here" -#define PS_STATE_DEAD 0 -#define PS_STATE_INIT 1 -#define PS_STATE_PROMPT1 2 -#define PS_STATE_PROMPT2 3 - -#define MAX_LEN_HOSTNAME 512 -#define MAX_FILE_LINE_LEN 1024 - -/* - * Routine for generating 16*8 bits of random data represented in ASCII hex - */ - -static int generate_cookie(unsigned char *buffer_33) -{ - static const char hexarray[] = "0123456789abcdef"; - int i, fd; - - /* fill buffer_33 with 32 hex characters (lower case) + '\0' */ - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - D(("failed to open /dev/urandom")); - return 0; - } - read(fd, buffer_33 + 16, 16); - close(fd); - - /* expand top 16 bytes into 32 nibbles */ - for (i=0; i<16; ++i) { - buffer_33[2*i ] = hexarray[(buffer_33[16+i] & 0xf0)>>4]; - buffer_33[2*i+1] = hexarray[(buffer_33[16+i] & 0x0f)]; - } - - buffer_33[32] = '\0'; - - return 1; -} - -/* - * XXX - This is a hack, and is fundamentally insecure. Its subject to - * all sorts of attacks not to mention the fact that all our secrets - * will be displayed on the command line for someone doing 'ps' to - * see. This is just for programming convenience in this instance, it - * needs to be replaced with the md5 code. Although I am loath to - * add yet another instance of md5 code to the Linux-PAM source code. - * [Need to think of a cleaner way to do this for the distribution as - * a whole...] - */ - -#define COMMAND_FORMAT "/bin/echo -n '%s|%s|%s'|/usr/bin/md5sum -" - -int create_digest(const char *d1, const char *d2, const char *d3, - char *buffer_33) -{ - int length; - char *buffer; - FILE *pipe; - - length = strlen(d1)+strlen(d2)+strlen(d3)+sizeof(COMMAND_FORMAT); - buffer = malloc(length); - if (buffer == NULL) { - D(("out of memory")); - return 0; - } - - sprintf(buffer, COMMAND_FORMAT, d1,d2,d3); - - D(("executing pipe [%s]", buffer)); - pipe = popen(buffer, "r"); - memset(buffer, 0, length); - free(buffer); - - if (pipe == NULL) { - D(("failed to launch pipe")); - return 0; - } - - if (fgets(buffer_33, 33, pipe) == NULL) { - D(("failed to read digest")); - return 0; - } - - if (strlen(buffer_33) != 32) { - D(("digest was not 32 chars")); - return 0; - } - - fclose(pipe); - - D(("done [%s]", buffer_33)); - - return 1; -} - -/* - * method to attempt to instruct the application's conversation function - */ - -static int converse(pam_handle_t *pamh, struct ps_state_s *new) -{ - int retval; - struct pam_conv *conv; - - D(("called")); - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) { - struct pam_message msg; - struct pam_response *single_reply; - const struct pam_message *msg_ptr; - - memset(&msg, 0, sizeof(msg)); - msg.msg_style = PAM_BINARY_PROMPT; - msg.msg = (const char *) new->current_prompt; - msg_ptr = &msg; - - single_reply = NULL; - retval = conv->conv(1, &msg_ptr, &single_reply, conv->appdata_ptr); - if (retval == PAM_SUCCESS) { - if ((single_reply == NULL) || (single_reply->resp == NULL)) { - retval == PAM_CONV_ERR; - } else { - new->current_reply = (pamc_bp_t) single_reply->resp; - single_reply->resp = NULL; - } - } - - if (single_reply) { - free(single_reply); - } - } - -#ifdef DEBUG - if (retval == PAM_SUCCESS) { - D(("reply has length=%d and control=%u", - PAM_BP_LENGTH(new->current_reply), - PAM_BP_CONTROL(new->current_reply))); - } - D(("returning %s", pam_strerror(pamh, retval))); -#endif - - return retval; -} - -/* - * identify the secret in question - */ - -#define SECRET_FILE_FORMAT "%s/.secret@here" - -char *identify_secret(char *identity, const char *user) -{ - struct passwd *pwd; - char *temp; - FILE *secrets; - int length_id; - - pwd = getpwnam(user); - if ((pwd == NULL) || (pwd->pw_dir == NULL)) { - D(("user [%s] is not known", user)); - } - - length_id = strlen(pwd->pw_dir) + sizeof(SECRET_FILE_FORMAT); - temp = malloc(length_id); - if (temp == NULL) { - D(("out of memory")); - pwd = NULL; - return NULL; - } - - sprintf(temp, SECRET_FILE_FORMAT, pwd->pw_dir); - pwd = NULL; - - D(("opening key file [%s]", temp)); - secrets = fopen(temp, "r"); - memset(temp, 0, length_id); - - if (secrets == NULL) { - D(("failed to open key file")); - return NULL; - } - - length_id = strlen(identity); - temp = malloc(MAX_FILE_LINE_LEN); - - for (;;) { - char *secret = NULL; - - if (fgets(temp, MAX_FILE_LINE_LEN, secrets) == NULL) { - fclose(secrets); - return NULL; - } - - D(("cf[%s][%s]", identity, temp)); - if (memcmp(temp, identity, length_id)) { - continue; - } - - D(("found entry")); - fclose(secrets); - - for (secret=temp+length_id; *secret; ++secret) { - if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) { - break; - } - } - - memmove(temp, secret, MAX_FILE_LINE_LEN-(secret-(temp+length_id))); - secret = temp; - - for (; *secret; ++secret) { - if (*secret == ' ' || *secret == '\n' || *secret == '\t') { - break; - } - } - - if (*secret) { - *secret = '\0'; - } - - D(("secret found [%s]", temp)); - - return temp; - } - - /* NOT REACHED */ -} - -/* - * function to perform the two message authentication process - * (with support for event driven conversation functions) - */ - -static int auth_sequence(pam_handle_t *pamh, - const struct ps_state_s *old, struct ps_state_s *new) -{ - const char *rhostname; - const char *rusername; - int retval; - - retval = pam_get_item(pamh, PAM_RUSER, (const void **) &rusername); - if ((retval != PAM_SUCCESS) || (rusername == NULL)) { - D(("failed to obtain an rusername")); - new->state = PS_STATE_DEAD; - return PAM_AUTH_ERR; - } - - retval = pam_get_item(pamh, PAM_RHOST, (const void **) &rhostname); - if ((retval != PAM_SUCCESS) || (rhostname == NULL)) { - D(("failed to identify local hostname: ", pam_strerror(pamh, retval))); - new->state = PS_STATE_DEAD; - return PAM_AUTH_ERR; - } - - D(("switch on new->state=%d [%s@%s]", new->state, rusername, rhostname)); - switch (new->state) { - - case PS_STATE_INIT: - { - const char *user = NULL; - - retval = pam_get_user(pamh, &user, NULL); - - if ((retval == PAM_SUCCESS) && (user == NULL)) { - D(("success but no username?")); - new->state = PS_STATE_DEAD; - retval = PAM_USER_UNKNOWN; - } - - if (retval != PAM_SUCCESS) { - if (retval == PAM_CONV_AGAIN) { - retval = PAM_INCOMPLETE; - } else { - new->state = PS_STATE_DEAD; - } - D(("state init failed: %s", pam_strerror(pamh, retval))); - return retval; - } - - /* nothing else in this 'case' can be retried */ - - new->username = strdup(user); - if (new->username == NULL) { - D(("out of memory")); - new->state = PS_STATE_DEAD; - return PAM_BUF_ERR; - } - - if (! generate_cookie(new->server_cookie)) { - D(("problem generating server cookie")); - new->state = PS_STATE_DEAD; - return PAM_ABORT; - } - - new->current_prompt = NULL; - PAM_BP_RENEW(&new->current_prompt, PAM_BPC_SELECT, - sizeof(PS_AGENT_ID) + strlen(rusername) + 1 - + strlen(rhostname) + 1 + 32); - sprintf(PAM_BP_WDATA(new->current_prompt), - PS_AGENT_ID "/%s@%s|%.32s", rusername, rhostname, - new->server_cookie); - - /* note, the BP is guaranteed by the spec to be <NUL> terminated */ - D(("initialization packet [%s]", PAM_BP_DATA(new->current_prompt))); - - /* fall through */ - new->state = PS_STATE_PROMPT1; - - D(("fall through to state_prompt1")); - } - - case PS_STATE_PROMPT1: - { - int i, length; - - /* send {secret@here/jdoe@client.host|<s_cookie>} */ - retval = converse(pamh, new); - if (retval != PAM_SUCCESS) { - if (retval == PAM_CONV_AGAIN) { - D(("conversation failed to complete")); - return PAM_INCOMPLETE; - } else { - new->state = PS_STATE_DEAD; - return retval; - } - } - - if (retval != PAM_SUCCESS) { - D(("failed to read ruser@rhost")); - new->state = PS_STATE_DEAD; - return PAM_AUTH_ERR; - } - - /* expect to receive the following {<seqid>|<a_cookie>} */ - if (new->current_reply == NULL) { - D(("converstation returned [%s] but gave no reply", - pam_strerror(pamh, retval))); - new->state = PS_STATE_DEAD; - return PAM_CONV_ERR; - } - - /* find | */ - length = PAM_BP_LENGTH(new->current_reply); - for (i=0; i<length; ++i) { - if (PAM_BP_RDATA(new->current_reply)[i] == '|') { - break; - } - } - if (i >= length) { - D(("malformed response (no |) of length %d", length)); - new->state = PS_STATE_DEAD; - return PAM_CONV_ERR; - } - if ((length - ++i) != 32) { - D(("cookie is incorrect length (%d,%d) %d != 32", - length, i, length-i)); - new->state = PS_STATE_DEAD; - return PAM_CONV_ERR; - } - - /* copy client cookie */ - memcpy(new->client_cookie, PAM_BP_RDATA(new->current_reply)+i, 32); - - /* generate a prompt that is length(seqid) + length(|) + 32 long */ - PAM_BP_RENEW(&new->current_prompt, PAM_BPC_OK, i+32); - /* copy the head of the response prompt */ - memcpy(PAM_BP_WDATA(new->current_prompt), - PAM_BP_RDATA(new->current_reply), i); - PAM_BP_RENEW(&new->current_reply, 0, 0); - - /* look up the secret */ - new->invalid_secret = 0; - - if (new->secret_data == NULL) { - char *ruser_rhost; - - ruser_rhost = malloc(strlen(rusername)+2+strlen(rhostname)); - if (ruser_rhost == NULL) { - D(("out of memory")); - new->state = PS_STATE_DEAD; - return PAM_BUF_ERR; - } - sprintf(ruser_rhost, "%s@%s", rusername, rhostname); - new->secret_data = identify_secret(ruser_rhost, new->username); - - memset(ruser_rhost, 0, strlen(ruser_rhost)); - free(ruser_rhost); - } - - if (new->secret_data == NULL) { - D(("secret not found for user")); - new->invalid_secret = 1; - - /* need to make up a secret */ - new->secret_data = malloc(32 + 1); - if (new->secret_data == NULL) { - D(("out of memory")); - new->state = PS_STATE_DEAD; - return PAM_BUF_ERR; - } - if (! generate_cookie(new->secret_data)) { - D(("what's up - no fake cookie generated?")); - new->state = PS_STATE_DEAD; - return PAM_ABORT; - } - } - - /* construct md5[<client_cookie>|<server_cookie>|<secret_data>] */ - if (! create_digest(new->client_cookie, new->server_cookie, - new->secret_data, - PAM_BP_WDATA(new->current_prompt)+i)) { - D(("md5 digesting failed")); - new->state = PS_STATE_DEAD; - return PAM_ABORT; - } - - /* prompt2 is now constructed - fall through to send it */ - } - - case PS_STATE_PROMPT2: - { - /* send {<seqid>|md5[<client_cookie>|<server_cookie>|<secret_data>]} */ - retval = converse(pamh, new); - if (retval != PAM_SUCCESS) { - if (retval == PAM_CONV_AGAIN) { - D(("conversation failed to complete")); - return PAM_INCOMPLETE; - } else { - new->state = PS_STATE_DEAD; - return retval; - } - } - - /* After we complete this section, we should not be able to - recall this authentication function. So, we force all - future calls into the weeds. */ - - new->state = PS_STATE_DEAD; - - /* expect reply:{md5[<secret_data>|<server_cookie>|<client_cookie>]} */ - - { - int cf; - char expectation[33]; - - if (!create_digest(new->secret_data, new->server_cookie, - new->client_cookie, expectation)) { - new->state = PS_STATE_DEAD; - return PAM_ABORT; - } - - cf = strcmp(expectation, PAM_BP_RDATA(new->current_reply)); - memset(expectation, 0, sizeof(expectation)); - if (cf || new->invalid_secret) { - D(("failed to authenticate")); - return PAM_AUTH_ERR; - } - } - - D(("correctly authenticated :)")); - return PAM_SUCCESS; - } - - default: - new->state = PS_STATE_DEAD; - - case PS_STATE_DEAD: - - D(("state is currently dead/unknown")); - return PAM_AUTH_ERR; - } - - fprintf(stderr, "pam_secret: this should not be reached\n"); - return PAM_ABORT; -} - -static void clean_data(pam_handle_t *pamh, void *datum, int error_status) -{ - struct ps_state_s *data = datum; - - D(("liberating datum=%p", datum)); - - if (data) { - D(("renew prompt")); - PAM_BP_RENEW(&data->current_prompt, 0, 0); - D(("renew reply")); - PAM_BP_RENEW(&data->current_reply, 0, 0); - D(("overwrite datum")); - memset(data, 0, sizeof(struct ps_state_s)); - D(("liberate datum")); - free(data); - } - - D(("done.")); -} - -/* - * front end for the authentication function - */ - -int pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval; - struct ps_state_s *new_data; - const struct ps_state_s *old_data; - - D(("called")); - - new_data = calloc(1, sizeof(struct ps_state_s)); - if (new_data == NULL) { - D(("out of memory")); - return PAM_BUF_ERR; - } - new_data->retval = PAM_SUCCESS; - - retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data); - if (retval == PAM_SUCCESS) { - new_data->state = old_data->state; - memcpy(new_data->server_cookie, old_data->server_cookie, 32); - memcpy(new_data->client_cookie, old_data->client_cookie, 32); - if (old_data->username) { - new_data->username = strdup(old_data->username); - } - if (old_data->secret_data) { - new_data->secret_data = strdup(old_data->secret_data); - } - if (old_data->current_prompt) { - int length; - - length = PAM_BP_LENGTH(old_data->current_prompt); - PAM_BP_RENEW(&new_data->current_prompt, - PAM_BP_CONTROL(old_data->current_prompt), length); - PAM_BP_FILL(new_data->current_prompt, 0, length, - PAM_BP_RDATA(old_data->current_prompt)); - } - /* don't need to duplicate current_reply */ - } else { - old_data = NULL; - new_data->state = PS_STATE_INIT; - } - - D(("call auth_sequence")); - new_data->retval = auth_sequence(pamh, old_data, new_data); - D(("returned from auth_sequence")); - - retval = pam_set_data(pamh, PS_STATE_ID, new_data, clean_data); - if (retval != PAM_SUCCESS) { - D(("unable to store new_data")); - } else { - retval = new_data->retval; - } - - old_data = new_data = NULL; - - D(("done (%d)", retval)); - return retval; -} - -/* - * front end for the credential setting function - */ - -#define AUTH_SESSION_TICKET_ENV_FORMAT "AUTH_SESSION_TICKET=" - -int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval; - const struct ps_state_s *old_data; - - D(("called")); - - /* XXX - need to pay attention to the various flavors of call */ - - /* XXX - need provide an option to turn this feature on/off: if - other modules want to supply an AUTH_SESSION_TICKET, we should - leave it up to the admin which module dominiates. */ - - retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data); - if (retval != PAM_SUCCESS) { - D(("no data to base decision on")); - return PAM_AUTH_ERR; - } - - /* - * If ok, export a derived shared secret session ticket to the - * client's PAM environment - the ticket has the form - * - * AUTH_SESSION_TICKET = - * md5[<server_cookie>|<secret_data>|<client_cookie>] - * - * This is a precursor to supporting a spoof resistant trusted - * path mechanism. This shared secret ticket can be used to add - * a hard-to-guess checksum to further authentication data. - */ - - retval = old_data->retval; - if (retval == PAM_SUCCESS) { - char envticket[sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)+32]; - - memcpy(envticket, AUTH_SESSION_TICKET_ENV_FORMAT, - sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)); - - if (! create_digest(old_data->server_cookie, old_data->secret_data, - old_data->client_cookie, - envticket+sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)-1 - )) { - D(("unable to generate a digest for session ticket")); - return PAM_ABORT; - } - - D(("putenv[%s]", envticket)); - retval = pam_putenv(pamh, envticket); - memset(envticket, 0, sizeof(envticket)); - } - - old_data = NULL; - D(("done (%d)", retval)); - - return retval; -} diff --git a/libpamc/test/regress/Makefile b/libpamc/test/regress/Makefile deleted file mode 100644 index ff63e5f0..00000000 --- a/libpamc/test/regress/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -CFLAGS = -g -I ../../include - -test.libpamc: test.libpamc.o - $(CC) -o $@ $< -L ../.. -lpamc - -clean: - rm -f test.libpamc test.libpamc.o diff --git a/libpamc/test/regress/run_test.sh b/libpamc/test/regress/run_test.sh deleted file mode 100755 index 6922f03d..00000000 --- a/libpamc/test/regress/run_test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -LD_LIBRARY_PATH=../.. ; export LD_LIBRARY_PATH -PAMC_AGENT_PATH="../agents" ; export PAMC_AGENT_PATH - -./test.libpamc diff --git a/libpamc/test/regress/test.libpamc.c b/libpamc/test/regress/test.libpamc.c deleted file mode 100644 index b7bc4e4b..00000000 --- a/libpamc/test/regress/test.libpamc.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * This is a small test program for testing libpamc against the - * secret@here agent. It does the same as the test.secret@here perl - * script in this directory, but via the libpamc API. - */ - -#include <stdio.h> -#include <string.h> -#include <security/pam_client.h> -#include <ctype.h> - -struct internal_packet { - int length; - int at; - char *buffer; -}; - - -void append_data(struct internal_packet *packet, int extra, const char *data) -{ - if ((extra + packet->at) >= packet->length) { - if (packet->length == 0) { - packet->length = 1000; - } - /* make sure we have at least a char extra space available */ - while (packet->length <= (extra + packet->at)) { - packet->length <<= 1; - } - packet->buffer = realloc(packet->buffer, packet->length); - if (packet->buffer == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - } - - if (data != NULL) { - memcpy(packet->at + packet->buffer, data, extra); - } - packet->at += extra; - - /* assisting string manipulation */ - packet->buffer[packet->at] = '\0'; -} - -void append_string(struct internal_packet *packet, const char *string, - int with_nul) -{ - append_data(packet, strlen(string) + (with_nul ? 1:0), string); -} - -char *identify_secret(char *identity) -{ - struct internal_packet temp_packet; - FILE *secrets; - int length_id; - - temp_packet.length = temp_packet.at = 0; - temp_packet.buffer = NULL; - - append_string(&temp_packet, "/home/", 0); - append_string(&temp_packet, getlogin(), 0); - append_string(&temp_packet, "/.secret@here", 1); - - secrets = fopen(temp_packet.buffer, "r"); - if (secrets == NULL) { - fprintf(stderr, "server: failed to open\n [%s]\n", - temp_packet.buffer); - exit(1); - } - - length_id = strlen(identity); - for (;;) { - char *secret = NULL; - temp_packet.at = 0; - - if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) { - fclose(secrets); - return NULL; - } - - if (memcmp(temp_packet.buffer, identity, length_id)) { - continue; - } - - fclose(secrets); - for (secret=temp_packet.buffer; *secret; ++secret) { - if (*secret == ' ' || *secret == '\n' || *secret == '\t') { - break; - } - } - for (; *secret; ++secret) { - if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) { - break; - } - } - - for (temp_packet.buffer=secret; *temp_packet.buffer; - ++temp_packet.buffer) { - if (*temp_packet.buffer == ' ' || *temp_packet.buffer == '\n' - || *temp_packet.buffer == '\t') { - break; - } - } - if (*temp_packet.buffer) { - *temp_packet.buffer = '\0'; - } - - return secret; - } - - /* NOT REACHED */ -} - -/* - * This is a hack, and is fundamentally insecure. All our secrets will be - * displayed on the command line for someone doing 'ps' to see. This - * is just for programming convenience in this instance, since this - * program is simply a regression test. The pam_secret module should - * not do this, but make use of md5 routines directly. - */ - -char *create_digest(int length, const char *raw) -{ - struct internal_packet temp_packet; - FILE *pipe; - - temp_packet.length = temp_packet.at = 0; - temp_packet.buffer = NULL; - - append_string(&temp_packet, "echo -n '", 0); - append_string(&temp_packet, raw, 0); - append_string(&temp_packet, "'|/usr/bin/md5sum -", 1); - - fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer); - - pipe = popen(temp_packet.buffer, "r"); - if (pipe == NULL) { - fprintf(stderr, "server: failed to run\n [%s]\n", temp_packet.buffer); - exit(1); - } - - temp_packet.at = 0; - append_data(&temp_packet, 32, NULL); - - if (fgets(temp_packet.buffer, 33, pipe) == NULL) { - fprintf(stderr, "server: failed to read digest\n"); - exit(1); - } - if (strlen(temp_packet.buffer) != 32) { - fprintf(stderr, "server: digest was not 32 chars?? [%s]\n", - temp_packet.buffer); - exit(1); - } - - fclose(pipe); - - return temp_packet.buffer; -} - -void packet_to_prompt(pamc_bp_t *prompt_p, __u8 control, - struct internal_packet *packet) -{ - PAM_BP_RENEW(prompt_p, control, packet->at); - PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer); - packet->at = 0; -} - -void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet) -{ - int data_length; - - data_length = PAM_BP_LENGTH(prompt); - packet->at = 0; - append_data(packet, data_length, NULL); - - PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer); - - fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n", - data_length, - PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt), - PAM_BP_RDATA(prompt)); -} - -int main(int argc, char **argv) -{ - pamc_handle_t pch; - pamc_bp_t prompt = NULL; - struct internal_packet packet_data, *packet; - char *temp_string, *secret, *user, *a_cookie, *seqid, *digest; - const char *cookie = "123451234512345"; - int retval; - - packet = &packet_data; - packet->length = 0; - packet->at = 0; - packet->buffer = NULL; - - pch = pamc_start(); - if (pch == NULL) { - fprintf(stderr, "server: unable to get a handle from libpamc\n"); - exit(1); - } - - temp_string = getlogin(); - if (temp_string == NULL) { - fprintf(stderr, "server: who are you?\n"); - exit(1); - } -#define DOMAIN "@local.host" - user = malloc(1+strlen(temp_string)+strlen(DOMAIN)); - if (user == NULL) { - fprintf(stderr, "server: out of memory for user id\n"); - exit(1); - } - sprintf(user, "%s%s", temp_string, DOMAIN); - - append_string(packet, "secret@here/", 0); - append_string(packet, user, 0); - append_string(packet, "|", 0); - append_string(packet, cookie, 0); - packet_to_prompt(&prompt, PAM_BPC_SELECT, packet); - - /* get the library to accept the first packet (which should load - the secret@here agent) */ - - retval = pamc_converse(pch, &prompt); - fprintf(stderr, "server: after conversation\n"); - if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) { - fprintf(stderr, "server: prompt had unexpected control type: %u\n", - PAM_BP_RCONTROL(prompt)); - exit(1); - } - - fprintf(stderr, "server: got a prompt back\n"); - - prompt_to_packet(prompt, packet); - - temp_string = strtok(packet->buffer, "|"); - if (temp_string == NULL) { - fprintf(stderr, "server: prompt does not contain anything"); - exit(1); - } - seqid = strdup(temp_string); - if (seqid == NULL) { - fprintf(stderr, "server: unable to store sequence id\n"); - } - - temp_string = strtok(NULL, "|"); - if (temp_string == NULL) { - fprintf(stderr, "server: no cookie from agent\n"); - exit(1); - } - a_cookie = strdup(temp_string); - if (a_cookie == NULL) { - fprintf(stderr, "server: no memory to store agent cookie\n"); - exit(1); - } - - fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie); - secret = identify_secret(user); - fprintf(stderr, "server: secret=%s\n", secret); - - /* now, we construct the response */ - packet->at = 0; - append_string(packet, a_cookie, 0); - append_string(packet, "|", 0); - append_string(packet, cookie, 0); - append_string(packet, "|", 0); - append_string(packet, secret, 0); - - fprintf(stderr, "server: get digest of %s\n", packet->buffer); - - digest = create_digest(packet->at, packet->buffer); - - fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest); - - packet->at = 0; - append_string(packet, seqid, 0); - append_string(packet, "|", 0); - append_string(packet, digest, 0); - packet_to_prompt(&prompt, PAM_BPC_OK, packet); - - retval = pamc_converse(pch, &prompt); - fprintf(stderr, "server: after 2nd conversation\n"); - if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) { - fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n", - PAM_BP_RCONTROL(prompt)); - exit(1); - } - - prompt_to_packet(prompt, packet); - PAM_BP_RENEW(&prompt, 0, 0); - - temp_string = strtok(packet->buffer, "|"); - if (temp_string == NULL) { - fprintf(stderr, "no digest from agent\n"); - exit(1); - } - temp_string = strdup(temp_string); - - packet->at = 0; - append_string(packet, secret, 0); - append_string(packet, "|", 0); - append_string(packet, cookie, 0); - append_string(packet, "|", 0); - append_string(packet, a_cookie, 0); - - fprintf(stderr, "server: get digest of %s\n", packet->buffer); - - digest = create_digest(packet->at, packet->buffer); - - fprintf(stderr, "server: digest=%s\n", digest); - - if (strcmp(digest, temp_string)) { - fprintf(stderr, "server: agent doesn't know the secret\n"); - fprintf(stderr, "server: agent says: [%s]\n" - "server: server says: [%s]\n", temp_string, digest); - exit(1); - } else { - fprintf(stderr, "server: agent seems to know the secret\n"); - - packet->at = 0; - append_string(packet, cookie, 0); - append_string(packet, "|", 0); - append_string(packet, secret, 0); - append_string(packet, "|", 0); - append_string(packet, a_cookie, 0); - - digest = create_digest(packet->at, packet->buffer); - - fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n", - digest); - } - - - retval = pamc_end(&pch); - - fprintf(stderr, "server: agent(s) were %shappy to terminate\n", - retval == PAM_BPC_TRUE ? "":"un"); - - exit(!retval); -} diff --git a/libpamc/test/regress/test.secret@here b/libpamc/test/regress/test.secret@here deleted file mode 100755 index 2e0b9b94..00000000 --- a/libpamc/test/regress/test.secret@here +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/perl - -## -## this is a test script for regressing changes to the secret@here PAM -## agent -## - -$^W = 1; -use strict; -use IPC::Open2; - -$| = 1; - -my $whoami = `/usr/bin/whoami`; chomp $whoami; -my $cookie = "12345"; -my $user_domain = "$whoami\@local.host"; - -my $pid = open2(\*Reader, \*Writer, "../agents/secret\@here blah") - or die "failed to load secret\@here agent"; - -unless (-f (getpwuid($<))[7]."/.secret\@here") { - print STDERR "server: ". "no " .(getpwuid($<))[7]. "/.secret\@here file\n"; - die "no config file"; -} - -WriteBinaryPrompt(\*Writer, 0x02, "secret\@here/$user_domain|$cookie"); - -my ($control, $data) = ReadBinaryPrompt(\*Reader); - -print STDERR "server: ". "reply: control=$control, data=$data\n"; -if ($control != 1) { - die "expected 1 (OK) for the first agent reply; got $control"; -} -my ($seqid, $a_cookie) = split '\|', $data; - -# server needs to convince agent that it knows the secret before -# agent will give a valid response -my $secret = IdentifyLocalSecret($user_domain); -my $digest = CreateDigest($a_cookie."|".$cookie."|".$secret); - -print STDERR "server: ". "digest = $digest\n"; -WriteBinaryPrompt(\*Writer, 0x01, "$seqid|$digest"); - -# The agent will authenticate us and then reply with its -# authenticating digest. we check that before we're done. - -($control, $data) = ReadBinaryPrompt(\*Reader); -if ($control != 0x03) { - die "server: agent did not reply with a 'done' prompt ($control)\n"; -} - -unless ($data eq CreateDigest($secret."|".$cookie."|".$a_cookie)) { - die "server: agent is not authenticated\n"; -} - -print STDERR "server: agent appears to know secret\n"; - -my $session_authenticated_ticket - = CreateDigest($cookie."|".$secret."|".$a_cookie); - -print STDERR "server: should putenv(" - ."\"AUTH_SESSION_TICKET=$session_authenticated_ticket\")\n"; - -exit 0; - -sub CreateDigest ($) { - my ($data) = @_; - - my $pid = open2(\*MD5out, \*MD5in, "/usr/bin/md5sum -") - or die "you'll need /usr/bin/md5sum installed"; - - my $oldfd = select MD5in; $|=1; select $oldfd; - print MD5in "$data"; - close MD5in; - my $reply = <MD5out>; - ($reply) = split /\s/, $reply; - print STDERR "server: ". "md5 said: <$reply>\n"; - close MD5out; - - return $reply; -} - -sub ReadBinaryPrompt ($) { - my ($fd) = @_; - - my $buffer = " "; - my $count = read($fd, $buffer, 5); - if ($count == 0) { - # no more packets to read - return (0, ""); - } - - if ($count != 5) { - # broken packet header - return (-1, ""); - } - - my ($length, $control) = unpack("N C", $buffer); - if ($length < 5) { - # broken packet length - return (-1, ""); - } - - my $data = ""; - $length -= 5; - while ($count = read($fd, $buffer, $length)) { - $data .= $buffer; - if ($count != $length) { - $length -= $count; - next; - } - - print STDERR "server: ". "data is [$data]\n"; - - return ($control, $data); - } - - # broken packet data - return (-1, ""); -} - -sub WriteBinaryPrompt ($$$) { - my ($fd, $control, $data) = @_; - - my $length = 5 + length($data); - printf STDERR "server: ". "{%d|0x%.2x|%s}\n", $length, $control, $data; - my $bp = pack("N C a*", $length, $control, $data); - print $fd $bp; - - print STDERR "server: ". "control passed to agent\@here\n"; -} - -sub IdentifyLocalSecret ($) { - my ($identifier) = @_; - my $secret; - - my $whoami = `/usr/bin/whoami` ; chomp $whoami; - if (open SECRETS, "< " .(getpwuid($<))[7]. "/.secret\@here") { - my $line; - while (defined ($line = <SECRETS>)) { - my ($id, $sec) = split /[\s]/, $line; - if ((defined $id) && ($id eq $identifier)) { - $secret = $sec; - last; - } - } - close SECRETS; - } - - return $secret; -} - diff --git a/modules/Makefile b/modules/Makefile deleted file mode 100644 index 93891029..00000000 --- a/modules/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# $Id$ -# -# Makefile -# -# This makefile controls the build process of shared and static PAM modules. -# -# - -include ../Make.Rules - -MODDIRS=$(shell /bin/ls -d pam_*) - -all: - @echo building the static modutil library - make -C pammodutil all - @echo modules sources available are: - @ls -d $(MODDIRS) 2>/dev/null ; echo :-------- - @echo -ifdef STATIC - rm -f ./_static_module_* -endif - @for i in $(MODDIRS) ; do \ - if [ -d $$i ]; then { \ - $(MAKE) -C $$i all ; \ - if [ $$? -ne 0 ]; then exit 1 ; fi ; \ - } elif [ -f ./.$$i ]; then { \ - cat ./.$$i ; \ - } fi ; \ - done - -download: - @./download-all - -install: - for i in $(MODDIRS) ; do \ - if [ -d $$i ]; then { \ - $(MAKE) -C $$i install ; \ - if [ $$? -ne 0 ]; then exit 1 ; fi ; \ - } fi ; \ - done - -remove: - for i in $(MODDIRS) ; do \ - if [ -d $$i ]; then { \ - $(MAKE) -C $$i remove ; \ - } fi ; \ - done - -lclean: - rm -f _static_module_* - -clean: lclean - for i in $(MODDIRS) ; do \ - if [ -d $$i ]; then { \ - $(MAKE) -C $$i clean ; \ - } fi ; \ - done - make -C pammodutil clean diff --git a/modules/README b/modules/README deleted file mode 100644 index 73d3cf0c..00000000 --- a/modules/README +++ /dev/null @@ -1,55 +0,0 @@ -This directory contains the modules. - -If you want to reserve a module name please email <pam-list@redhat.com> -and announce its name. Andrew Morgan, <morgan@linux.kernel.org>, will -add it to the Makefile in the next release of Linux-PAM. - -As of Linux-PAM-0.40 modules can optionally conform to the static -modules conventions. - -This file was updated for Linux-PAM-0.53. - -The conventions are as follows: - -There are only 6 functions that a module may declare as "public" they -fall into 4 managment groups as follows: - - functions Management group - ------------------------------------------ ---------------- - pam_sm_authenticate, pam_sm_setcred, PAM_SM_AUTH - pam_sm_acct_mgmt, PAM_SM_ACCOUNT - pam_sm_open_session, pam_sm_close_session, PAM_SM_SESSION - pam_sm_chauthtok PAM_SM_PASSWORD - -If a module contains definitions for any of the above functions, it -must supply definitions for all of the functions in the corresponding -management group. - -The header file that defines the ANSI prototypes for these functions -is <security/pam_modules.h> . In the case that the module wishes to -offer the functions of a given managment group, it must #define -PAM_SM_XXX, where XXX is one of the above four tokens. These -definitions must occur *prior* to the -#include <security/pam_modules.h> line. - -The pam_sm_... functions should be defined to be of type 'PAM_EXTERN int'. - -In the case that a module is being compiled with PAM_STATIC #define'd -it should also define a globally accessible structure -_"NAME"_modstruct containing references to each of the functions -defined by the module. (this structure is defined in -<security/pam_modules.h>. "NAME" is the title of the module -(eg. "pam_deny") - -If a module wants to be included in the static libpam.a its Makefile -should execute "register_static" with appropriate arguments (in this -directory). - -[ -For SIMPLE working examples, see - - ./modules/pam_deny/* and ./modules/pam_rootok/* -.] - -Andrew Morgan -96/11/10 diff --git a/modules/Simple.Rules b/modules/Simple.Rules deleted file mode 100644 index 2d79b00c..00000000 --- a/modules/Simple.Rules +++ /dev/null @@ -1,95 +0,0 @@ -# $Id$ -# -# For simple modules with no significant dependencies, set $(TITLE) -# and include this file. -# -# There are a few ways to customize this set of rules. Namely, define -# -# $(MODULE_SIMPLE_EXTRACLEAN) -# $(MODULE_SIMPLE_CLEAN) -# $(MODULE_SIMPLE_REMOVE) -# $(MODULE_SIMPLE_INSTALL) -# $(MODULE_SIMPLE_EXTRALIBS) - other things to link with the module -# $(MODULE_SIMPLE_EXTRAFILES) - other files to build (no .c suffix) -# - -LIBFILES = $(TITLE) $(MODULE_SIMPLE_EXTRAFILES) -LIBSRC = $(addsuffix .c,$(LIBFILES)) -LIBOBJ = $(addsuffix .o,$(LIBFILES)) -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -LIBOBJS = $(addprefix static/,$(LIBOBJ)) - -LINK_PAMMODUTILS = -L../pammodutil -lpammodutil -INCLUDE_PAMMODUTILS = -I../pammodutil/include - -ifdef DYNAMIC -LIBSHARED = $(TITLE).so -endif - -ifdef STATIC -LIBSTATIC = lib$(TITLE).o -endif - -####################### don't edit below ####################### - -all: dirs $(LIBSHARED) $(LIBSTATIC) register - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(INCLUDE_PAMMODUTILS) $(DYNAMIC) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(INCLUDE_PAMMODUTILS) $(STATIC) $(TARGET_ARCH) -c $< -o $@ - -dirs: -ifdef DYNAMIC - $(MKDIR) ./dynamic -endif -ifdef STATIC - $(MKDIR) ./static -endif - -register: -ifdef STATIC - ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) -endif - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) -endif - -ifdef DYNAMIC -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) $(MODULE_SIMPLE_EXTRALIBS) $(NEED_LINK_LIB_C) $(LINK_PAMMODUTILS) - -endif - -ifdef STATIC -$(LIBOBJS): $(LIBSRC) -endif - -ifdef STATIC -$(LIBSTATIC): $(LIBOBJS) - $(LD) -r -o $@ $(LIBOBJS) $(MODULE_SIMPLE_EXTRALIBS) $(LINK_PAMMODUTILS) -endif - -install: all - $(MKDIR) $(FAKEROOT)$(SECUREDIR) -ifdef DYNAMIC - $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) -endif - $(MODULE_SIMPLE_INSTALL) - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so - $(MODULE_SIMPLE_REMOVE) - -clean: - rm -f $(LIBOBJD) $(LIBOBJS) core *~ - $(MODULE_SIMPLE_CLEAN) - rm -f *.a *.o *.so *.bak - rm -rf dynamic static - $(MODULE_SIMPLE_EXTRACLEAN) - -.c.o: - $(CC) $(CFLAGS) -c $< - diff --git a/modules/dont_makefile b/modules/dont_makefile deleted file mode 100644 index b7e11834..00000000 --- a/modules/dont_makefile +++ /dev/null @@ -1,21 +0,0 @@ -######################################################################### -# $Id$ -######################################################################### -# This is a makefile that does nothing. It is designed to be included -# by module Makefile-s when they are not compatable with the local -# system -######################################################################### - -all: - @echo "This module will not be compiled on this system" - -remove: clean - -install: clean - -clean: - @echo "Nothing to do" - -######################################################################### -# all over.. -######################################################################### diff --git a/modules/download-all b/modules/download-all deleted file mode 100755 index 427d0bba..00000000 --- a/modules/download-all +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# -# $Id$ -# -cat <<EOT -For a number of reasons it is not practical for Linux-PAM to be -distributed with every module out there. However, this shell script -is intended as a convenient way for users to download modules from the -'net in some semiautomated fashion. - -Please feel free to send (pam-list@redhat.com) snippets of code that -will help others to download and unpack your favorite module into the -Linux-PAM source tree. Especially welcome are snippets of the -following form: - -ncftp ftp://my.ftpsite.org/pub/fluff/pam_fluff.tar.gz -rm -fr pam_fluff -tar zvfx pam_fluff.tar.gz - -Cheers - -Andrew -morgan@linux.kernel.org -EOT - -# --- insert your snippets below --- - -# --- insert your snippets above --- - -exit 0 diff --git a/modules/install_conf b/modules/install_conf deleted file mode 100755 index 80f6be29..00000000 --- a/modules/install_conf +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -FAKEROOT=$1 -CONFD=$1$2 -CONFILE=$1$3 -MODULE=$4 -CONF=$5 - -IGNORE_AGE=./.ignore_age -QUIET_INSTALL=../../.quiet_install - -echo - -if [ -f "$QUIET_INSTALL" ]; then - if [ ! -f "$CONFILE" ]; then - yes="y" - else - yes="skip" - fi -elif [ -f "$IGNORE_AGE" ]; then - echo "you don't want to be bothered with the age of your $CONFILE file" - yes="n" -elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then - if [ -f "$CONFILE" ]; then - echo "An older $MODULE configuration file already exists ($CONFILE)" - echo "Do you wish to copy the $CONF file in this distribution" - echo "to $CONFILE ? (y/n) [skip] " - read yes - else - yes="y" - fi -else - yes="skip" -fi - -if [ "$yes" = "y" ]; then - mkdir -p $CONFD - echo " copying $CONF to $CONFILE" - cp $CONF $CONFILE -else - echo " Skipping $CONF installation" - if [ "$yes" = "n" ]; then - touch "$IGNORE_AGE" - fi -fi - -echo - -exit 0 diff --git a/modules/pam_access/.cvsignore b/modules/pam_access/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_access/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_access/Makefile b/modules/pam_access/Makefile deleted file mode 100644 index d93c9f40..00000000 --- a/modules/pam_access/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# - -include ../../Make.Rules - -TITLE=pam_access -LOCAL_CONFILE=./access.conf -INSTALLED_CONFILE=$(SCONFIGD)/access.conf - -DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" -CFLAGS += $(DEFS) - -MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" -MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) -MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age - -include ../Simple.Rules diff --git a/modules/pam_access/README b/modules/pam_access/README deleted file mode 100644 index ddd4725f..00000000 --- a/modules/pam_access/README +++ /dev/null @@ -1,44 +0,0 @@ -# Description of its configuration file -# -# (The default config file is "/etc/security/access.conf". This -# default can be overridden with a module config argument -# 'accessfile=<full-path>'): -# -# Login access control table. -# -# When someone logs in, the table is scanned for the first entry that -# matches the (user, host) combination, or, in case of non-networked -# logins, the first entry that matches the (user, tty) combination. The -# permissions field of that table entry determines whether the login will -# be accepted or refused. -# -# Format of the login access control table is three fields separated by a -# ":" character: -# -# permission : users : origins -# -# The first field should be a "+" (access granted) or "-" (access denied) -# character. -# -# The second field should be a list of one or more login names, group -# names, or ALL (always matches). A pattern of the form user@host is -# matched when the login name matches the "user" part, and when the -# "host" part matches the local machine name. -# -# The third field should be a list of one or more tty names (for -# non-networked logins), host names, domain names (begin with "."), host -# addresses, internet network numbers (end with "."), ALL (always -# matches) or LOCAL (matches any string that does not contain a "." -# character). -# -# If you run NIS you can use @netgroupname in host or user patterns; this -# even works for @usergroup@@hostgroup patterns. Weird. -# -# The EXCEPT operator makes it possible to write very compact rules. -# -# The group file is searched only when a name does not match that of the -# logged-in user. Both the user's primary group is matched, as well as -# groups in which users are explicitly listed. -# -# Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15 -############################################################################ diff --git a/modules/pam_access/access.conf b/modules/pam_access/access.conf deleted file mode 100644 index dbaadf67..00000000 --- a/modules/pam_access/access.conf +++ /dev/null @@ -1,58 +0,0 @@ -# Login access control table. -# -# When someone logs in, the table is scanned for the first entry that -# matches the (user, host) combination, or, in case of non-networked -# logins, the first entry that matches the (user, tty) combination. The -# permissions field of that table entry determines whether the login will -# be accepted or refused. -# -# Format of the login access control table is three fields separated by a -# ":" character: -# -# [Note, if you supply a 'fieldsep=|' argument to the pam_access.so -# module, you can change the field separation character to be -# '|'. This is useful for configurations where you are trying to use -# pam_access with X applications that provide PAM_TTY values that are -# the display variable like "host:0".] -# -# permission : users : origins -# -# The first field should be a "+" (access granted) or "-" (access denied) -# character. -# -# The second field should be a list of one or more login names, group -# names, or ALL (always matches). A pattern of the form user@host is -# matched when the login name matches the "user" part, and when the -# "host" part matches the local machine name. -# -# The third field should be a list of one or more tty names (for -# non-networked logins), host names, domain names (begin with "."), host -# addresses, internet network numbers (end with "."), ALL (always -# matches) or LOCAL (matches any string that does not contain a "." -# character). -# -# If you run NIS you can use @netgroupname in host or user patterns; this -# even works for @usergroup@@hostgroup patterns. Weird. -# -# The EXCEPT operator makes it possible to write very compact rules. -# -# The group file is searched only when a name does not match that of the -# logged-in user. Both the user's primary group is matched, as well as -# groups in which users are explicitly listed. -# -############################################################################## -# -# Disallow console logins to all but a few accounts. -# -#-:ALL EXCEPT wheel shutdown sync:LOCAL -# -# Disallow non-local logins to privileged accounts (group wheel). -# -#-:wheel:ALL EXCEPT LOCAL .win.tue.nl -# -# Some accounts are not allowed to login from anywhere: -# -#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL -# -# All other accounts are allowed to login from anywhere. -# diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c deleted file mode 100644 index 4005c93b..00000000 --- a/modules/pam_access/pam_access.c +++ /dev/null @@ -1,497 +0,0 @@ -/* pam_access module */ - -/* - * Written by Alexei Nogin <alexei@nogin.dnttm.ru> 1997/06/15 - * (I took login_access from logdaemon-5.6 and converted it to PAM - * using parts of pam_time code.) - * - ************************************************************************ - * Copyright message from logdaemon-5.6 (original file name DISCLAIMER) - ************************************************************************ - * Copyright 1995 by Wietse Venema. All rights reserved. Individual files - * may be covered by other copyrights (as noted in the file itself.) - * - * This material was originally written and compiled by Wietse Venema at - * Eindhoven University of Technology, The Netherlands, in 1990, 1991, - * 1992, 1993, 1994 and 1995. - * - * Redistribution and use in source and binary forms are permitted - * provided that this entire copyright notice is duplicated in all such - * copies. - * - * This software is provided "as is" and without any expressed or implied - * warranties, including, without limitation, the implied warranties of - * merchantibility and fitness for any particular purpose. - ************************************************************************* - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <stdarg.h> -#include <syslog.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pwd.h> -#include <grp.h> -#include <errno.h> -#include <ctype.h> -#include <sys/utsname.h> - -#ifndef BROKEN_NETWORK_MATCH -# include <netdb.h> -# include <sys/socket.h> -#endif - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_ACCOUNT - -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -int strcasecmp(const char *s1, const char *s2); - -/* login_access.c from logdaemon-5.6 with several changes by A.Nogin: */ - - /* - * This module implements a simple but effective form of login access - * control based on login names and on host (or domain) names, internet - * addresses (or network numbers), or on terminal line names in case of - * non-networked logins. Diagnostics are reported through syslog(3). - * - * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. - */ - -#if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 64) -#undef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -#ifdef DEFAULT_CONF_FILE -# define PAM_ACCESS_CONFIG DEFAULT_CONF_FILE -#else -# define PAM_ACCESS_CONFIG "/etc/security/access.conf" -#endif - - /* Delimiters for fields and for lists of users, ttys or hosts. */ - -static const char *fs = ":"; /* field separator */ -static const char sep[] = ", \t"; /* list-element separator */ - - /* Constants to be used in assignments only, not in comparisons... */ - -#define YES 1 -#define NO 0 - - /* - * A structure to bundle up all login-related information to keep the - * functional interfaces as generic as possible. - */ -struct login_info { - struct passwd *user; - char *from; - const char *config_file; - const char *service; -}; - -/* --- static functions for checking whether the user should be let in --- */ - -static void _log_err(const char *format, ... ) -{ - va_list args; - - va_start(args, format); - openlog("pam_access", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(LOG_ERR, format, args); - va_end(args); - closelog(); -} - -/* Parse module config arguments */ - -static int parse_args(struct login_info *loginfo, int argc, const char **argv) -{ - int i; - - for (i=0; i<argc; ++i) { - if (!strncmp("fieldsep=", argv[i], 9)) { - - /* the admin wants to override the default field separators */ - fs = argv[i]+9; - - } else if (!strncmp("accessfile=", argv[i], 11)) { - FILE *fp = fopen(11 + argv[i], "r"); - - if (fp) { - loginfo->config_file = 11 + argv[i]; - fclose(fp); - } else { - _log_err("for service [%s] failed to open accessfile=[%s]" - , loginfo->service, 11 + argv[i]); - return 0; - } - - } else { - _log_err("unrecognized option [%s]", argv[i]); - } - } - - return 1; /* OK */ -} - -typedef int match_func (char *, struct login_info *); - -static int list_match (char *, struct login_info *, - match_func *); -static int user_match (char *, struct login_info *); -static int from_match (char *, struct login_info *); -static int string_match (char *, char *); - -/* login_access - match username/group and host/tty with access control file */ - -static int login_access(struct login_info *item) -{ - FILE *fp; - char line[BUFSIZ]; - char *perm; /* becomes permission field */ - char *users; /* becomes list of login names */ - char *froms; /* becomes list of terminals or hosts */ - int match = NO; - int end; - int lineno = 0; /* for diagnostics */ - - /* - * Process the table one line at a time and stop at the first match. - * Blank lines and lines that begin with a '#' character are ignored. - * Non-comment lines are broken at the ':' character. All fields are - * mandatory. The first field should be a "+" or "-" character. A - * non-existing table means no access control. - */ - - if ((fp = fopen(item->config_file, "r"))!=NULL) { - while (!match && fgets(line, sizeof(line), fp)) { - lineno++; - if (line[end = strlen(line) - 1] != '\n') { - _log_err("%s: line %d: missing newline or line too long", - item->config_file, lineno); - continue; - } - if (line[0] == '#') - continue; /* comment line */ - while (end > 0 && isspace(line[end - 1])) - end--; - line[end] = 0; /* strip trailing whitespace */ - if (line[0] == 0) /* skip blank lines */ - continue; - if (!(perm = strtok(line, fs)) - || !(users = strtok((char *) 0, fs)) - || !(froms = strtok((char *) 0, fs)) - || strtok((char *) 0, fs)) { - _log_err("%s: line %d: bad field count", - item->config_file, lineno); - continue; - } - if (perm[0] != '+' && perm[0] != '-') { - _log_err("%s: line %d: bad first field", - item->config_file, lineno); - continue; - } - match = (list_match(froms, item, from_match) - && list_match(users, item, user_match)); - } - (void) fclose(fp); - } else if (errno != ENOENT) { - _log_err("cannot open %s: %m", item->config_file); - } - return (match == 0 || (line[0] == '+')); -} - -/* list_match - match an item against a list of tokens with exceptions */ - -static int list_match(char *list, struct login_info *item, match_func *match_fn) -{ - char *tok; - int match = NO; - - /* - * Process tokens one at a time. We have exhausted all possible matches - * when we reach an "EXCEPT" token or the end of the list. If we do find - * a match, look for an "EXCEPT" list and recurse to determine whether - * the match is affected by any exceptions. - */ - - for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { - if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ - break; - if ((match = (*match_fn) (tok, item))) /* YES */ - break; - } - /* Process exceptions to matches. */ - - if (match != NO) { - while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) - /* VOID */ ; - if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) - return (match); - } - return (NO); -} - -/* myhostname - figure out local machine name */ - -static char * myhostname(void) -{ - static char name[MAXHOSTNAMELEN + 1]; - - gethostname(name, MAXHOSTNAMELEN); - name[MAXHOSTNAMELEN] = 0; - return (name); -} - -/* netgroup_match - match group against machine or user */ - -static int netgroup_match(char *group, char *machine, char *user) -{ -#ifdef NIS - static char *mydomain = 0; - - if (mydomain == 0) - yp_get_default_domain(&mydomain); - return (innetgr(group, machine, user, mydomain)); -#else - _log_err("NIS netgroup support not configured"); - return (NO); -#endif -} - -/* user_match - match a username against one token */ - -static int user_match(char *tok, struct login_info *item) -{ - char *string = item->user->pw_name; - struct login_info fake_item; - struct group *group; - int i; - char *at; - - /* - * If a token has the magic value "ALL" the match always succeeds. - * Otherwise, return YES if the token fully matches the username, if the - * token is a group that contains the username, or if the token is the - * name of the user's primary group. - */ - - if ((at = strchr(tok + 1, '@')) != 0) { /* split user@host pattern */ - *at = 0; - fake_item.from = myhostname(); - return (user_match(tok, item) && from_match(at + 1, &fake_item)); - } else if (tok[0] == '@') { /* netgroup */ - return (netgroup_match(tok + 1, (char *) 0, string)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if ((group = getgrnam(tok))) { /* try group membership */ - if (item->user->pw_gid == group->gr_gid) - return (YES); - for (i = 0; group->gr_mem[i]; i++) - if (strcasecmp(string, group->gr_mem[i]) == 0) - return (YES); - } - return (NO); -} - -/* from_match - match a host or tty against a list of tokens */ - -static int from_match(char *tok, struct login_info *item) -{ - char *string = item->from; - int tok_len; - int str_len; - - /* - * If a token has the magic value "ALL" the match always succeeds. Return - * YES if the token fully matches the string. If the token is a domain - * name, return YES if it matches the last fields of the string. If the - * token has the magic value "LOCAL", return YES if the string does not - * contain a "." character. If the token is a network number, return YES - * if it matches the head of the string. - */ - - if (tok[0] == '@') { /* netgroup */ - return (netgroup_match(tok + 1, string, (char *) 0)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if (tok[0] == '.') { /* domain: match last fields */ - if ((str_len = strlen(string)) > (tok_len = strlen(tok)) - && strcasecmp(tok, string + str_len - tok_len) == 0) - return (YES); - } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ - if (strchr(string, '.') == 0) - return (YES); -#ifdef BROKEN_NETWORK_MATCH - } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ - && strncmp(tok, string, tok_len) == 0) { - return (YES); -#else /* BROKEN_NETWORK_MATCH */ - } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { - /* - The code below does a more correct check if the address specified - by "string" starts from "tok". - 1998/01/27 Andrey V. Savochkin <saw@msu.ru> - */ - - struct hostent *h; - char hn[3+1+3+1+3+1+3+1+1]; - int r; - - h = gethostbyname(string); - if (h == NULL) - return (NO); - if (h->h_addrtype != AF_INET) - return (NO); - if (h->h_length != 4) - return (NO); /* only IPv4 addresses (SAW) */ - r = snprintf(hn, sizeof(hn), "%u.%u.%u.%u.", - (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], - (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]); - if (r < 0 || r >= sizeof(hn)) - return (NO); - if (!strncmp(tok, hn, tok_len)) - return (YES); -#endif /* BROKEN_NETWORK_MATCH */ - } - return (NO); -} - -/* string_match - match a string against one token */ - -static int string_match(char *tok, char *string) -{ - - /* - * If the token has the magic value "ALL" the match always succeeds. - * Otherwise, return YES if the token fully matches the string. - */ - - if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ - return (YES); - } else if (strcasecmp(tok, string) == 0) { /* try exact match */ - return (YES); - } - return (NO); -} - -/* end of login_access.c */ - -int strcasecmp(const char *s1, const char *s2) -{ - while ((toupper(*s1)==toupper(*s2)) && (*s1) && (*s2)) {s1++; s2++;} - return(toupper(*s1)-toupper(*s2)); -} - -/* --- public account management functions --- */ - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - struct login_info loginfo; - const char *user=NULL, *service=NULL; - char *from=NULL; - struct passwd *user_pw; - - if ((pam_get_item(pamh, PAM_SERVICE, (const void **)&service) - != PAM_SUCCESS) || (service == NULL) || (*service == ' ')) { - _log_err("cannot find the service name"); - return PAM_ABORT; - } - - /* set username */ - - if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL - || *user == '\0') { - _log_err("cannot determine the user's name"); - return PAM_USER_UNKNOWN; - } - - /* remote host name */ - - if (pam_get_item(pamh, PAM_RHOST, (const void **)&from) - != PAM_SUCCESS) { - _log_err("cannot find the remote host name"); - return PAM_ABORT; - } - - if ((from==NULL) || (*from=='\0')) { - - /* local login, set tty name */ - - if (pam_get_item(pamh, PAM_TTY, (const void **)&from) != PAM_SUCCESS - || from == NULL) { - D(("PAM_TTY not set, probing stdin")); - from = ttyname(STDIN_FILENO); - if (from == NULL) { - _log_err("couldn't get the tty name"); - return PAM_ABORT; - } - if (pam_set_item(pamh, PAM_TTY, from) != PAM_SUCCESS) { - _log_err("couldn't set tty name"); - return PAM_ABORT; - } - } - if (strncmp("/dev/",from,5) == 0) { /* strip leading /dev/ */ - from += 5; - } - - } - - if ((user_pw=getpwnam(user))==NULL) return (PAM_USER_UNKNOWN); - - /* - * Bundle up the arguments to avoid unnecessary clumsiness later on. - */ - loginfo.user = user_pw; - loginfo.from = from; - loginfo.service = service; - loginfo.config_file = PAM_ACCESS_CONFIG; - - /* parse the argument list */ - - if (!parse_args(&loginfo, argc, argv)) { - _log_err("failed to parse the module arguments"); - return PAM_ABORT; - } - - if (login_access(&loginfo)) { - return (PAM_SUCCESS); - } else { - _log_err("access denied for user `%s' from `%s'",user,from); - return (PAM_PERM_DENIED); - } -} - -/* end of module definition */ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_access_modstruct = { - "pam_access", - NULL, - NULL, - pam_sm_acct_mgmt, - NULL, - NULL, - NULL -}; -#endif - diff --git a/modules/pam_cracklib/.cvsignore b/modules/pam_cracklib/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_cracklib/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_cracklib/Makefile b/modules/pam_cracklib/Makefile deleted file mode 100644 index 5f6371ef..00000000 --- a/modules/pam_cracklib/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@kernel.org> 2000/10/08 -# - -include ../../Make.Rules - -TITLE=pam_cracklib - -ifeq ($(HAVE_LIBCRACK),yes) -BUILD_THIS_MODULE=yes -MODULE_SIMPLE_EXTRALIBS=-lcrack - -# These two should really be provided by ../../pam_aconf.h -CFLAGS+=-DCRACKLIB_DICTPATH=\"$(CRACKLIB_DICTPATH)\" - -ifeq ($(HAVE_LIBCRYPT),yes) - MODULE_SIMPLE_EXTRALIBS += -lcrypt -endif - -endif - -ifeq ($(BUILD_THIS_MODULE),yes) - include ../Simple.Rules -else - include ../dont_makefile -endif diff --git a/modules/pam_cracklib/README b/modules/pam_cracklib/README deleted file mode 100644 index 69662f73..00000000 --- a/modules/pam_cracklib/README +++ /dev/null @@ -1,37 +0,0 @@ - -pam_cracklib: - check the passwd against dictionary words. - -RECOGNIZED ARGUMENTS: - debug verbose log - - type=XXX alter the message printed as a prompt to the user. - the message printed is in the form - "New XXX password: ". - Default XXX=UNIX - - retry=N Prompt user at most N times before returning with - error. Default N=1. - - difok=N How many characters can be the same in the new - password relative to the old - difignore=N How many characters long should the password be - before we ignore difok. - - minlen=N The minimum simplicity count for a good password. - - dcredit=N - ucredit=N - lcredit=N - ocredit=N Weight, digits, upper, lower, other characters with - count N. Use these values to compute the - 'unsimplicity' of the password. - - use_authtok Get the proposed password from PAM_AUTHTOK - -MODULE SERVICES PROVIDED: - passwd chauthtok - -AUTHOR: - Cristian Gafton <gafton@redhat.com> - diff --git a/modules/pam_cracklib/pam_cracklib.c b/modules/pam_cracklib/pam_cracklib.c deleted file mode 100644 index bc98d2f6..00000000 --- a/modules/pam_cracklib/pam_cracklib.c +++ /dev/null @@ -1,888 +0,0 @@ -/* - * pam_cracklib module - * $Id$ - */ - -/* - * 0.9. switch to using a distance algorithm in similar() - * 0.86. added support for setting minimum numbers of digits, uppers, - * lowers, and others - * 0.85. added six new options to use this with long passwords. - * 0.8. tidied output and improved D(()) usage for debugging. - * 0.7. added support for more obscure checks for new passwd. - * 0.6. root can reset user passwd to any values (it's only warned) - * 0.5. supports retries - 'retry=N' argument - * 0.4. added argument 'type=XXX' for 'New XXX password' prompt - * 0.3. Added argument 'debug' - * 0.2. new password is feeded to cracklib for verify after typed once - * 0.1. First release - */ - -/* - * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 - * Long password support by Philip W. Dalrymple <pwd@mdtsoft.com> 1997/07/18 - * See the end of the file for Copyright Information - * - * Modification for long password systems (>8 chars). The original - * module had problems when used in a md5 password system in that it - * allowed too short passwords but required that at least half of the - * bytes in the new password did not appear in the old one. this - * action is still the default and the changes should not break any - * current user. This modification adds 6 new options, one to set the - * number of bytes in the new password that are not in the old one, - * the other five to control the length checking, these are all - * documented (or will be before anyone else sees this code) in the PAM - * S.A.G. in the section on the cracklib module. - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#ifdef HAVE_CRYPT_H -# include <crypt.h> -#endif -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <ctype.h> - -extern char *FascistCheck(char *pw, const char *dictpath); - -#ifndef CRACKLIB_DICTPATH -#define CRACKLIB_DICTPATH "/usr/share/dict/cracklib_dict" -#endif - -#define PROMPT1 "New %s%spassword: " -#define PROMPT2 "Retype new %s%spassword: " -#define MISTYPED_PASS "Sorry, passwords do not match" - -#ifdef MIN -#undef MIN -#endif -#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-Cracklib", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ -#define PAM_DEBUG_ARG 0x0001 - -struct cracklib_options { - int retry_times; - int diff_ok; - int diff_ignore; - int min_length; - int dig_credit; - int up_credit; - int low_credit; - int oth_credit; - int use_authtok; - char prompt_type[BUFSIZ]; -}; - -#define CO_RETRY_TIMES 1 -#define CO_DIFF_OK 5 -#define CO_DIFF_IGNORE 23 -#define CO_MIN_LENGTH 9 -# define CO_MIN_LENGTH_BASE 5 -#define CO_DIG_CREDIT 1 -#define CO_UP_CREDIT 1 -#define CO_LOW_CREDIT 1 -#define CO_OTH_CREDIT 1 -#define CO_USE_AUTHTOK 0 - -static int _pam_parse(struct cracklib_options *opt, int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - char *ep = NULL; - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strncmp(*argv,"type=",5)) - strncpy(opt->prompt_type, *argv+5, sizeof(opt->prompt_type) - 1); - else if (!strncmp(*argv,"retry=",6)) { - opt->retry_times = strtol(*argv+6,&ep,10); - if (!ep || (opt->retry_times < 1)) - opt->retry_times = CO_RETRY_TIMES; - } else if (!strncmp(*argv,"difok=",6)) { - opt->diff_ok = strtol(*argv+6,&ep,10); - if (!ep || (opt->diff_ok < 0)) - opt->diff_ok = CO_DIFF_OK; - } else if (!strncmp(*argv,"difignore=",10)) { - opt->diff_ignore = strtol(*argv+10,&ep,10); - if (!ep || (opt->diff_ignore < 0)) - opt->diff_ignore = CO_DIFF_IGNORE; - } else if (!strncmp(*argv,"minlen=",7)) { - opt->min_length = strtol(*argv+7,&ep,10); - if (!ep || (opt->min_length < CO_MIN_LENGTH_BASE)) - opt->min_length = CO_MIN_LENGTH_BASE; - } else if (!strncmp(*argv,"dcredit=",8)) { - opt->dig_credit = strtol(*argv+8,&ep,10); - if (!ep) - opt->dig_credit = 0; - } else if (!strncmp(*argv,"ucredit=",8)) { - opt->up_credit = strtol(*argv+8,&ep,10); - if (!ep) - opt->up_credit = 0; - } else if (!strncmp(*argv,"lcredit=",8)) { - opt->low_credit = strtol(*argv+8,&ep,10); - if (!ep) - opt->low_credit = 0; - } else if (!strncmp(*argv,"ocredit=",8)) { - opt->oth_credit = strtol(*argv+8,&ep,10); - if (!ep) - opt->oth_credit = 0; - } else if (!strncmp(*argv,"use_authtok",11)) { - opt->use_authtok = 1; - } else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - opt->prompt_type[sizeof(opt->prompt_type) - 1] = '\0'; - - return ctrl; -} - -/* Helper functions */ - -/* this is a front-end for module-application conversations */ -static int converse(pam_handle_t *pamh, int ctrl, int nargs, - struct pam_message **message, - struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - - if ( retval == PAM_SUCCESS ) { - retval = conv->conv(nargs, (const struct pam_message **)message, - response, conv->appdata_ptr); - if (retval != PAM_SUCCESS && (ctrl && PAM_DEBUG_ARG)) { - _pam_log(LOG_DEBUG, "conversation failure [%s]", - pam_strerror(pamh, retval)); - } - } else { - _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]", - pam_strerror(pamh, retval)); - } - - return retval; /* propagate error status */ -} - -static int make_remark(pam_handle_t *pamh, unsigned int ctrl, - int type, const char *text) -{ - struct pam_message *pmsg[1], msg[1]; - struct pam_response *resp; - int retval; - - pmsg[0] = &msg[0]; - msg[0].msg = text; - msg[0].msg_style = type; - resp = NULL; - - retval = converse(pamh, ctrl, 1, pmsg, &resp); - if (retval == PAM_SUCCESS) - _pam_drop_reply(resp, 1); - - return retval; -} - -/* use this to free strings. ESPECIALLY password strings */ -static char *_pam_delete(register char *xx) -{ - _pam_overwrite(xx); - free(xx); - return NULL; -} - -/* - * can't be a palindrome - like `R A D A R' or `M A D A M' - */ -static int palindrome(const char *old, const char *new) -{ - int i, j; - - i = strlen (new); - - for (j = 0;j < i;j++) - if (new[i - j - 1] != new[j]) - return 0; - - return 1; -} - -/* - * Calculate how different two strings are in terms of the number of - * character removals, additions, and changes needed to go from one to - * the other - */ - -static int distdifferent(const char *old, const char *new, int i, int j) -{ - char c, d; - - if ((i == 0) || (strlen(old) <= i)) { - c = 0; - } else { - c = old[i - 1]; - } - if ((j == 0) || (strlen(new) <= i)) { - d = 0; - } else { - d = new[j - 1]; - } - return (c != d); -} - -static int distcalculate(int **distances, const char *old, const char *new, - int i, int j) -{ - int tmp = 0; - - if (distances[i][j] != -1) { - return distances[i][j]; - } - - tmp = distcalculate(distances, old, new, i - 1, j - 1); - tmp = MIN(tmp, distcalculate(distances, old, new, i, j - 1)); - tmp = MIN(tmp, distcalculate(distances, old, new, i - 1, j)); - tmp += distdifferent(old, new, i, j); - - distances[i][j] = tmp; - - return tmp; -} - -static int distance(const char *old, const char *new) -{ - int **distances = NULL; - int m, n, i, j, r; - - m = strlen(old); - n = strlen(new); - distances = malloc(sizeof(int*) * (m + 1)); - - for (i = 0; i <= m; i++) { - distances[i] = malloc(sizeof(int) * (n + 1)); - for(j = 0; j <= n; j++) { - distances[i][j] = -1; - } - } - for (i = 0; i <= m; i++) { - distances[i][0] = i; - } - for (j = 0; j <= n; j++) { - distances[0][j] = j; - } - distances[0][0] = 0; - - r = distcalculate(distances, old, new, m, n); - - for (i = 0; i <= m; i++) { - memset(distances[i], 0, sizeof(int) * (n + 1)); - free(distances[i]); - } - free(distances); - - return r; -} - -static int similar(struct cracklib_options *opt, - const char *old, const char *new) -{ - if (distance(old, new) >= opt->diff_ok) { - return 0; - } - - if (strlen(new) >= (strlen(old) * 2)) { - return 0; - } - - /* passwords are too similar */ - return 1; -} - -/* - * a nice mix of characters. - */ -static int simple(struct cracklib_options *opt, - const char *old, const char *new) -{ - int digits = 0; - int uppers = 0; - int lowers = 0; - int others = 0; - int size; - int i; - - for (i = 0;new[i];i++) { - if (isdigit (new[i])) - digits++; - else if (isupper (new[i])) - uppers++; - else if (islower (new[i])) - lowers++; - else - others++; - } - - /* - * The scam was this - a password of only one character type - * must be 8 letters long. Two types, 7, and so on. - * This is now changed, the base size and the credits or defaults - * see the docs on the module for info on these parameters, the - * defaults cause the effect to be the same as before the change - */ - - if ((opt->dig_credit >= 0) && (digits > opt->dig_credit)) - digits = opt->dig_credit; - - if ((opt->up_credit >= 0) && (uppers > opt->up_credit)) - uppers = opt->up_credit; - - if ((opt->low_credit >= 0) && (lowers > opt->low_credit)) - lowers = opt->low_credit; - - if ((opt->oth_credit >= 0) && (others > opt->oth_credit)) - others = opt->oth_credit; - - size = opt->min_length; - - if (opt->dig_credit >= 0) - size -= digits; - else if (digits < opt->dig_credit * -1) - return 1; - - if (opt->up_credit >= 0) - size -= uppers; - else if (uppers < opt->up_credit * -1) - return 1; - - if (opt->low_credit >= 0) - size -= lowers; - else if (lowers < opt->low_credit * -1) - return 1; - - if (opt->oth_credit >= 0) - size -= others; - else if (others < opt->oth_credit * -1) - return 1; - - if (size <= i) - return 0; - - return 1; -} - -static char * str_lower(char *string) -{ - char *cp; - - for (cp = string; *cp; cp++) - *cp = tolower(*cp); - return string; -} - -static const char * password_check(struct cracklib_options *opt, const char *old, const char *new) -{ - const char *msg = NULL; - char *oldmono, *newmono, *wrapped; - - if (strcmp(new, old) == 0) { - msg = "is the same as the old one"; - return msg; - } - - newmono = str_lower(x_strdup(new)); - oldmono = str_lower(x_strdup(old)); - wrapped = malloc(strlen(oldmono) * 2 + 1); - strcpy (wrapped, oldmono); - strcat (wrapped, oldmono); - - if (palindrome(oldmono, newmono)) - msg = "is a palindrome"; - - if (!msg && strcmp(oldmono, newmono) == 0) - msg = "case changes only"; - - if (!msg && similar(opt, oldmono, newmono)) - msg = "is too similar to the old one"; - - if (!msg && simple(opt, old, new)) - msg = "is too simple"; - - if (!msg && strstr(wrapped, newmono)) - msg = "is rotated"; - - memset(newmono, 0, strlen(newmono)); - memset(oldmono, 0, strlen(oldmono)); - memset(wrapped, 0, strlen(wrapped)); - free(newmono); - free(oldmono); - free(wrapped); - - return msg; -} - - -#define OLD_PASSWORDS_FILE "/etc/security/opasswd" - -static const char * check_old_password(const char *forwho, const char *newpass) -{ - static char buf[16384]; - char *s_luser, *s_uid, *s_npas, *s_pas; - const char *msg = NULL; - FILE *opwfile; - - opwfile = fopen(OLD_PASSWORDS_FILE, "r"); - if (opwfile == NULL) - return NULL; - - while (fgets(buf, 16380, opwfile)) { - if (!strncmp(buf, forwho, strlen(forwho))) { - buf[strlen(buf)-1] = '\0'; - s_luser = strtok(buf, ":,"); - s_uid = strtok(NULL, ":,"); - s_npas = strtok(NULL, ":,"); - s_pas = strtok(NULL, ":,"); - while (s_pas != NULL) { - if (!strcmp(crypt(newpass, s_pas), s_pas)) { - msg = "has been already used"; - break; - } - s_pas = strtok(NULL, ":,"); - } - break; - } - } - fclose(opwfile); - - return msg; -} - - -static int _pam_unix_approve_pass(pam_handle_t *pamh, - unsigned int ctrl, - struct cracklib_options *opt, - const char *pass_old, - const char *pass_new) -{ - const char *msg = NULL; - const char *user; - int retval; - - if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { - if (ctrl && PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "bad authentication token"); - make_remark(pamh, ctrl, PAM_ERROR_MSG, - pass_new == NULL ? - "No password supplied":"Password unchanged" ); - return PAM_AUTHTOK_ERR; - } - - /* - * if one wanted to hardwire authentication token strength - * checking this would be the place - */ - msg = password_check(opt, pass_old,pass_new); - if (!msg) { - retval = pam_get_item(pamh, PAM_USER, (const void **)&user); - if (retval != PAM_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_ERR,"Can not get username"); - return PAM_AUTHTOK_ERR; - } - } - msg = check_old_password(user, pass_new); - } - - if (msg) { - char remark[BUFSIZ]; - - memset(remark,0,sizeof(remark)); - snprintf(remark,sizeof(remark),"BAD PASSWORD: %s",msg); - if (ctrl && PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE, "new passwd fails strength check: %s", - msg); - make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); - return PAM_AUTHTOK_ERR; - }; - return PAM_SUCCESS; - -} - -/* The Main Thing (by Cristian Gafton, CEO at this module :-) - * (stolen from http://home.netscape.com) - */ -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - struct cracklib_options options; - - D(("called.")); - - options.retry_times = CO_RETRY_TIMES; - options.diff_ok = CO_DIFF_OK; - options.diff_ignore = CO_DIFF_IGNORE; - options.min_length = CO_MIN_LENGTH; - options.dig_credit = CO_DIG_CREDIT; - options.up_credit = CO_UP_CREDIT; - options.low_credit = CO_LOW_CREDIT; - options.oth_credit = CO_OTH_CREDIT; - options.use_authtok = CO_USE_AUTHTOK; - memset(options.prompt_type, 0, BUFSIZ); - strcpy(options.prompt_type,"UNIX"); - - ctrl = _pam_parse(&options, argc, argv); - - if (flags & PAM_PRELIM_CHECK) { - /* Check for passwd dictionary */ - struct stat st; - char buf[sizeof(CRACKLIB_DICTPATH)+10]; - - D(("prelim check")); - - memset(buf,0,sizeof(buf)); /* zero the buffer */ - snprintf(buf,sizeof(buf),"%s.pwd",CRACKLIB_DICTPATH); - - if (!stat(buf,&st) && st.st_size) - return PAM_SUCCESS; - else { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"dict path '%s'[.pwd] is invalid", - CRACKLIB_DICTPATH); - return PAM_ABORT; - } - - /* Not reached */ - return PAM_SERVICE_ERR; - - } else if (flags & PAM_UPDATE_AUTHTOK) { - int retval; - char *token1, *token2, *oldtoken; - struct pam_message msg[1],*pmsg[1]; - struct pam_response *resp; - const char *cracklib_dictpath = CRACKLIB_DICTPATH; - char prompt[BUFSIZ]; - - D(("do update")); - retval = pam_get_item(pamh, PAM_OLDAUTHTOK, - (const void **)&oldtoken); - if (retval != PAM_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_ERR,"Can not get old passwd"); - oldtoken=NULL; - retval = PAM_SUCCESS; - } - - do { - /* - * make sure nothing inappropriate gets returned - */ - token1 = token2 = NULL; - - if (!options.retry_times) { - D(("returning %s because maxtries reached", - pam_strerror(pamh, retval))); - return retval; - } - - /* Planned modus operandi: - * Get a passwd. - * Verify it against cracklib. - * If okay get it a second time. - * Check to be the same with the first one. - * set PAM_AUTHTOK and return - */ - - if (options.use_authtok == 1) { - const char *item = NULL; - - retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item); - if (retval != PAM_SUCCESS) { - /* very strange. */ - _pam_log(LOG_ALERT - ,"pam_get_item returned error to pam_cracklib" - ); - } else if (item != NULL) { /* we have a password! */ - token1 = x_strdup(item); - item = NULL; - } else { - retval = PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } - - } else { - /* Prepare to ask the user for the first time */ - memset(prompt,0,sizeof(prompt)); - snprintf(prompt,sizeof(prompt),PROMPT1, - options.prompt_type, options.prompt_type[0]?" ":""); - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_PROMPT_ECHO_OFF; - msg[0].msg = prompt; - - resp = NULL; - retval = converse(pamh, ctrl, 1, pmsg, &resp); - if (resp != NULL) { - /* interpret the response */ - if (retval == PAM_SUCCESS) { /* a good conversation */ - token1 = x_strdup(resp[0].resp); - if (token1 == NULL) { - _pam_log(LOG_NOTICE, - "could not recover authentication token 1"); - retval = PAM_AUTHTOK_RECOVER_ERR; - } - } - /* - * tidy up the conversation (resp_retcode) is ignored - */ - _pam_drop_reply(resp, 1); - } else { - retval = (retval == PAM_SUCCESS) ? - PAM_AUTHTOK_RECOVER_ERR:retval ; - } - } - - if (retval != PAM_SUCCESS) { - if (ctrl && PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG,"unable to obtain a password"); - continue; - } - - D(("testing password, retval = %s", pam_strerror(pamh, retval))); - /* now test this passwd against cracklib */ - { - char *crack_msg; - char remark[BUFSIZ]; - - bzero(remark,sizeof(remark)); - D(("against cracklib")); - if ((crack_msg = FascistCheck(token1, cracklib_dictpath))) { - if (ctrl && PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG,"bad password: %s",crack_msg); - snprintf(remark,sizeof(remark),"BAD PASSWORD: %s", crack_msg); - make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); - if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) - retval = PAM_AUTHTOK_ERR; - else - retval = PAM_SUCCESS; - } else { - /* check it for strength too... */ - D(("for strength")); - if (oldtoken) { - retval = _pam_unix_approve_pass(pamh,ctrl,&options, - oldtoken,token1); - if (retval != PAM_SUCCESS) { - if (getuid() || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) - retval = PAM_AUTHTOK_ERR; - else - retval = PAM_SUCCESS; - } - } - } - } - - D(("after testing: retval = %s", pam_strerror(pamh, retval))); - /* if cracklib/strength check said it is a bad passwd... */ - if ((retval != PAM_SUCCESS) && (retval != PAM_IGNORE)) { - int temp_unused; - - temp_unused = pam_set_item(pamh, PAM_AUTHTOK, NULL); - token1 = _pam_delete(token1); - continue; - } - - /* Now we have a good passwd. Ask for it once again */ - - if (options.use_authtok == 0) { - bzero(prompt,sizeof(prompt)); - snprintf(prompt,sizeof(prompt),PROMPT2, - options.prompt_type, options.prompt_type[0]?" ":""); - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_PROMPT_ECHO_OFF; - msg[0].msg = prompt; - - resp = NULL; - retval = converse(pamh, ctrl, 1, pmsg, &resp); - if (resp != NULL) { - /* interpret the response */ - if (retval == PAM_SUCCESS) { /* a good conversation */ - token2 = x_strdup(resp[0].resp); - if (token2 == NULL) { - _pam_log(LOG_NOTICE, - "could not recover authentication token 2"); - retval = PAM_AUTHTOK_RECOVER_ERR; - } - } - /* - * tidy up the conversation (resp_retcode) is ignored - */ - _pam_drop_reply(resp, 1); - } else { - retval = (retval == PAM_SUCCESS) ? - PAM_AUTHTOK_RECOVER_ERR:retval ; - } - - if (retval != PAM_SUCCESS) { - if (ctrl && PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG - ,"unable to obtain the password a second time"); - continue; - } - - /* Hopefully now token1 and token2 the same password ... */ - if (strcmp(token1,token2) != 0) { - /* tell the user */ - make_remark(pamh, ctrl, PAM_ERROR_MSG, MISTYPED_PASS); - token1 = _pam_delete(token1); - token2 = _pam_delete(token2); - pam_set_item(pamh, PAM_AUTHTOK, NULL); - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"Password mistyped"); - retval = PAM_AUTHTOK_RECOVER_ERR; - continue; - } - - /* Yes, the password was typed correct twice - * we store this password as an item - */ - - { - const char *item = NULL; - - retval = pam_set_item(pamh, PAM_AUTHTOK, token1); - - /* clean up */ - token1 = _pam_delete(token1); - token2 = _pam_delete(token2); - - if ( (retval != PAM_SUCCESS) || - ((retval = pam_get_item(pamh, PAM_AUTHTOK, - (const void **)&item) - ) != PAM_SUCCESS) ) { - _pam_log(LOG_CRIT, "error manipulating password"); - continue; - } - item = NULL; /* break link to password */ - return PAM_SUCCESS; - } - } - - } while (options.retry_times--); - - } else { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE, "UNKNOWN flags setting %02X",flags); - return PAM_SERVICE_ERR; - } - - /* Not reached */ - return PAM_SERVICE_ERR; -} - - - -#ifdef PAM_STATIC -/* static module data */ -struct pam_module _pam_cracklib_modstruct = { - "pam_cracklib", - NULL, - NULL, - NULL, - NULL, - NULL, - pam_sm_chauthtok -}; -#endif - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996. - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The following copyright was appended for the long password support - * added with the libpam 0.58 release: - * - * Modificaton Copyright (c) Philip W. Dalrymple III <pwd@mdtsoft.com> - * 1997. All rights reserved - * - * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_debug/.cvsignore b/modules/pam_debug/.cvsignore deleted file mode 100644 index dd17fdcf..00000000 --- a/modules/pam_debug/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -dynamic -static diff --git a/modules/pam_debug/Makefile b/modules/pam_debug/Makefile deleted file mode 100644 index ae22cade..00000000 --- a/modules/pam_debug/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_debug - -include ../Simple.Rules diff --git a/modules/pam_debug/README b/modules/pam_debug/README deleted file mode 100644 index b537e3a7..00000000 --- a/modules/pam_debug/README +++ /dev/null @@ -1,15 +0,0 @@ -# $Id$ -# - -This module returns what its module arguments tell it to return. It -can be used for debugging libpam and/or an application. - -Here are some example ways to use it: - -auth requisite pam_permit.so -auth [success=2 default=ok] pam_debug.so auth=perm_denied cred=success -auth [default=reset] pam_debug.so auth=success cred=perm_denied -auth [success=done default=die] pam_debug.so -auth optional pam_debug.so auth=perm_denied cred=perm_denied -auth sufficient pam_debug.so auth=success cred=success - diff --git a/modules/pam_debug/pam_debug.c b/modules/pam_debug/pam_debug.c deleted file mode 100644 index 152b977c..00000000 --- a/modules/pam_debug/pam_debug.c +++ /dev/null @@ -1,175 +0,0 @@ -/* pam_permit module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@kernel.org> 2001/02/04 - * - */ - -#define DEFAULT_USER "nobody" - -#include <stdio.h> - -/* - * This module is intended as a debugging aide for determining how - * the PAM stack is operating. - * - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -#define _PAM_ACTION_UNDEF (-10) -#include "../../libpam/pam_tokens.h" - -/* --- authentication management functions --- */ - -static int state(pam_handle_t *pamh, const char *text) -{ - int retval; - struct pam_conv *conv; - struct pam_message msg[1], *mesg[1]; - struct pam_response *response; - - retval = pam_get_item(pamh, PAM_CONV, (const void **)&conv); - if ((retval != PAM_SUCCESS) || (conv == NULL)) { - D(("failed to obtain conversation function")); - return PAM_ABORT; - } - - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = text; - mesg[0] = &msg[0]; - - retval = conv->conv(1, (const struct pam_message **) mesg, - &response, conv->appdata_ptr); - if (retval != PAM_SUCCESS) { - D(("conversation failed")); - } - - return retval; -} - -static int parse_args(int retval, const char *event, - pam_handle_t *pamh, int argc, const char **argv) -{ - int i; - - for (i=0; i<argc; ++i) { - int length = strlen(event); - if (!strncmp(event, argv[i], length) && (argv[i][length] == '=')) { - int j; - const char *return_string = argv[i] + (length+1); - - for (j=0; j<_PAM_RETURN_VALUES; ++j) { - if (!strcmp(return_string, _pam_token_returns[j])) { - retval = j; - state(pamh, argv[i]); - break; - } - } - break; - } - } - - return retval; -} - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - int retval; - const char *user=NULL; - - /* - * authentication requires we know who the user wants to be - */ - retval = pam_get_user(pamh, &user, NULL); - if (retval != PAM_SUCCESS) { - D(("get user returned error: %s", pam_strerror(pamh,retval))); - return retval; - } - if (user == NULL || *user == '\0') { - D(("username not known")); - pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); - } - user = NULL; /* clean up */ - - retval = parse_args(PAM_SUCCESS, "auth", pamh, argc, argv); - - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return parse_args(PAM_SUCCESS, "cred", pamh, argc, argv); -} - -/* --- account management functions --- */ - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return parse_args(PAM_SUCCESS, "acct", pamh, argc, argv); -} - -/* --- password management --- */ - -PAM_EXTERN -int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - if (flags & PAM_PRELIM_CHECK) { - return parse_args(PAM_SUCCESS, "prechauthtok", pamh, argc, argv); - } else { - return parse_args(PAM_SUCCESS, "chauthtok", pamh, argc, argv); - } -} - -/* --- session management --- */ - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc, - const char **argv) -{ - return parse_args(PAM_SUCCESS, "open_session", pamh, argc, argv); -} - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return parse_args(PAM_SUCCESS, "close_session", pamh, argc, argv); -} - -/* end of module definition */ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_permit_modstruct = { - "pam_debug", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok -}; - -#endif diff --git a/modules/pam_deny/.cvsignore b/modules/pam_deny/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_deny/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_deny/Makefile b/modules/pam_deny/Makefile deleted file mode 100644 index 7dd7b4fd..00000000 --- a/modules/pam_deny/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_deny - -include ../Simple.Rules diff --git a/modules/pam_deny/README b/modules/pam_deny/README deleted file mode 100644 index 6683bdcc..00000000 --- a/modules/pam_deny/README +++ /dev/null @@ -1,4 +0,0 @@ -# $Id$ -# - -this module always fails, it ignores all options. diff --git a/modules/pam_deny/pam_deny.c b/modules/pam_deny/pam_deny.c deleted file mode 100644 index b474751d..00000000 --- a/modules/pam_deny/pam_deny.c +++ /dev/null @@ -1,81 +0,0 @@ -/* pam_permit module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 - * - */ - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> - -/* --- authentication management functions --- */ - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_AUTH_ERR; -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_CRED_UNAVAIL; -} - -/* --- account management functions --- */ - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_ACCT_EXPIRED; -} - -/* --- password management --- */ - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_AUTHTOK_ERR; -} - -/* --- session management --- */ - -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SYSTEM_ERR; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SYSTEM_ERR; -} - -/* end of module definition */ - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_deny_modstruct = { - "pam_deny", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok -}; -#endif diff --git a/modules/pam_env/.cvsignore b/modules/pam_env/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_env/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_env/Makefile b/modules/pam_env/Makefile deleted file mode 100644 index fa711ce3..00000000 --- a/modules/pam_env/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# - -include ../../Make.Rules - -TITLE=pam_env -LOCAL_CONFILE=./pam_env.conf-example -INSTALLED_CONFILE=$(SCONFIGD)/pam_env.conf - -DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" -CFLAGS += $(DEFS) - -MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" -MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) -MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age - -include ../Simple.Rules diff --git a/modules/pam_env/README b/modules/pam_env/README deleted file mode 100644 index 04df323b..00000000 --- a/modules/pam_env/README +++ /dev/null @@ -1,72 +0,0 @@ -# $Date$ -# $Author$ -# $Id$ -# -# This is the configuration file for pam_env, a PAM module to load in -# a configurable list of environment variables for a -# -# The original idea for this came from Andrew G. Morgan ... -#<quote> -# Mmm. Perhaps you might like to write a pam_env module that reads a -# default environment from a file? I can see that as REALLY -# useful... Note it would be an "auth" module that returns PAM_IGNORE -# for the auth part and sets the environment returning PAM_SUCCESS in -# the setcred function... -#</quote> -# -# What I wanted was the REMOTEHOST variable set, purely for selfish -# reasons, and AGM didn't want it added to the SimpleApps login -# program (which is where I added the patch). So, my first concern is -# that variable, from there there are numerous others that might/would -# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER ..... -# -# Of course, these are a different kind of variable than REMOTEHOST in -# that they are things that are likely to be configured by -# administrators rather than set by logging in, how to treat them both -# in the same config file? -# -# Here is my idea: -# -# Each line starts with the variable name, there are then two possible -# options for each variable DEFAULT and OVERRIDE. -# DEFAULT allows and administrator to set the value of the -# variable to some default value, if none is supplied then the empty -# string is assumed. The OVERRIDE option tells pam_env that it should -# enter in its value (overriding the default value) if there is one -# to use. OVERRIDE is not used, "" is assumed and no override will be -# done. -# -# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] -# -# (Possibly non-existent) environment variables may be used in values -# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may -# be used in values using the @{string} syntax. Both the $ and @ -# characters can be backslash escaped to be used as literal values -# values can be delimited with "", escaped " not supported. -# -# -# First, some special variables -# -# Set the REMOTEHOST variable for any hosts that are remote, default -# to "localhost" rather than not being set at all -REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST} -# -# Set the DISPLAY variable if it seems reasonable -DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY} -# -# -# Now some simple variables -# -PAGER DEFAULT=less -MANPAGER DEFAULT=less -LESS DEFAULT="M q e h15 z23 b80" -NNTPSERVER DEFAULT=localhost -PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\ -:/usr/bin:/usr/local/bin/X11:/usr/bin/X11 -# -# silly examples of escaped variables, just to show how they work. -# -DOLLAR DEFAULT=\$ -DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR} -DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST} -ATSIGN DEFAULT="" OVERRIDE=\@ diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c deleted file mode 100644 index ba04c15e..00000000 --- a/modules/pam_env/pam_env.c +++ /dev/null @@ -1,842 +0,0 @@ -/* pam_mail module */ - -/* - * $Id$ - * - * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31 - * Inspired by Andrew Morgan <morgan@kernel.org>, who also supplied the - * template for this file (via pam_mail) - */ - -#ifndef DEFAULT_CONF_FILE -#define DEFAULT_CONF_FILE "/etc/security/pam_env.conf" -#endif - -#define DEFAULT_ETC_ENVFILE "/etc/environment" -#define DEFAULT_READ_ENVFILE 1 - -#include <security/_pam_aconf.h> - -#include <ctype.h> -#include <errno.h> -#include <pwd.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH /* This is primarily a AUTH_SETCRED module */ -#define PAM_SM_SESSION /* But I like to be friendly */ -#define PAM_SM_PASSWORD /* "" */ -#define PAM_SM_ACCOUNT /* "" */ - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* This little structure makes it easier to keep variables together */ - -typedef struct var { - char *name; - char *value; - char *defval; - char *override; -} VAR; - -#define BUF_SIZE 1024 -#define MAX_ENV 8192 - -#define GOOD_LINE 0 -#define BAD_LINE 100 /* This must be > the largest PAM_* error code */ - -#define DEFINE_VAR 101 -#define UNDEFINE_VAR 102 -#define ILLEGAL_VAR 103 - -static int _assemble_line(FILE *, char *, int); -static int _parse_line(char *, VAR *); -static int _check_var(pam_handle_t *, VAR *); /* This is the real meat */ -static void _clean_var(VAR *); -static int _expand_arg(pam_handle_t *, char **); -static const char * _pam_get_item_byname(pam_handle_t *, const char *); -static int _define_var(pam_handle_t *, VAR *); -static int _undefine_var(pam_handle_t *, VAR *); - -/* This is a flag used to designate an empty string */ -static char quote='Z'; - -/* some syslogging */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-env", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x01 -#define PAM_NEW_CONF_FILE 0x02 -#define PAM_ENV_SILENT 0x04 -#define PAM_NEW_ENV_FILE 0x10 - -static int _pam_parse(int flags, int argc, const char **argv, char **conffile, - char **envfile, int *readenv) -{ - int ctrl=0; - - - /* step through arguments */ - for (; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strncmp(*argv,"conffile=",9)) { - *conffile = x_strdup(9+*argv); - if (*conffile != NULL) { - D(("new Configuration File: %s", *conffile)); - ctrl |= PAM_NEW_CONF_FILE; - } else { - _log_err(LOG_CRIT, - "Configuration file specification missing argument - ignored"); - } - } else if (!strncmp(*argv,"envfile=",8)) { - *envfile = x_strdup(8+*argv); - if (*envfile != NULL) { - D(("new Env File: %s", *envfile)); - ctrl |= PAM_NEW_ENV_FILE; - } else { - _log_err(LOG_CRIT, - "Env file specification missing argument - ignored"); - } - } else if (!strncmp(*argv,"readenv=",8)) - *readenv = atoi(8+*argv); - else - _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - - return ctrl; -} - -static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile) -{ - int retval; - const char *file; - char buffer[BUF_SIZE]; - FILE *conf; - VAR Var, *var=&Var; - - var->name=NULL; var->defval=NULL; var->override=NULL; - D(("Called.")); - - if (ctrl & PAM_NEW_CONF_FILE) { - file = *conffile; - } else { - file = DEFAULT_CONF_FILE; - } - - D(("Config file name is: %s", file)); - - /* - * Lets try to open the config file, parse it and process - * any variables found. - */ - - if ((conf = fopen(file,"r")) == NULL) { - _log_err(LOG_ERR, "Unable to open config file: %s", - strerror(errno)); - return PAM_IGNORE; - } - - /* _pam_assemble_line will provide a complete line from the config file, with all - * comments removed and any escaped newlines fixed up - */ - - while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) { - D(("Read line: %s", buffer)); - - if ((retval = _parse_line(buffer, var)) == GOOD_LINE) { - retval = _check_var(pamh, var); - - if (DEFINE_VAR == retval) { - retval = _define_var(pamh, var); - - } else if (UNDEFINE_VAR == retval) { - retval = _undefine_var(pamh, var); - } - } - if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval - && BAD_LINE != retval && PAM_BAD_ITEM != retval) break; - - _clean_var(var); - - } /* while */ - - (void) fclose(conf); - - /* tidy up */ - _clean_var(var); /* We could have got here prematurely, this is safe though */ - _pam_overwrite(*conffile); - _pam_drop(*conffile); - file = NULL; - D(("Exit.")); - return (retval<0?PAM_ABORT:PAM_SUCCESS); -} - -static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) -{ - int retval=PAM_SUCCESS, i, t; - const char *file; - char buffer[BUF_SIZE], *key, *mark; - FILE *conf; - - if (ctrl & PAM_NEW_ENV_FILE) - file = *env_file; - else - file = DEFAULT_ETC_ENVFILE; - - D(("Env file name is: %s", file)); - - if ((conf = fopen(file,"r")) == NULL) { - D(("Unable to open env file: %s", strerror(errno))); - return PAM_ABORT; - } - - while (_assemble_line(conf, buffer, BUF_SIZE) > 0) { - D(("Read line: %s", buffer)); - key = buffer; - - /* skip leading white space */ - key += strspn(key, " \n\t"); - - /* skip blanks lines and comments */ - if (!key || key[0] == '#') - continue; - - /* skip over "export " if present so we can be compat with - bash type declerations */ - if (strncmp(key, "export ", (size_t) 7) == 0) - key += 7; - - /* now find the end of value */ - mark = key; - while(mark[0] != '\n' && mark[0] != '#' && mark[0] != '\0') - mark++; - if (mark[0] != '\0') - mark[0] = '\0'; - - /* - * sanity check, the key must be alpha-numeric - */ - - for ( i = 0 ; key[i] != '=' && key[i] != '\0' ; i++ ) - if (!isalnum(key[i]) && key[i] != '_') { - D(("key is not alpha numeric - '%s', ignoring", key)); - continue; - } - - /* now we try to be smart about quotes around the value, - but not too smart, we can't get all fancy with escaped - values like bash */ - if (key[i] == '=' && (key[++i] == '\"' || key[i] == '\'')) { - for ( t = i+1 ; key[t] != '\0' ; t++) - if (key[t] != '\"' && key[t] != '\'') - key[i++] = key[t]; - else if (key[t+1] != '\0') - key[i++] = key[t]; - key[i] = '\0'; - } - - /* set the env var, if it fails, we break out of the loop */ - retval = pam_putenv(pamh, key); - if (retval != PAM_SUCCESS) { - D(("error setting env \"%s\"", key)); - break; - } - } - - (void) fclose(conf); - - /* tidy up */ - _pam_overwrite(*env_file); - _pam_drop(*env_file); - file = NULL; - D(("Exit.")); - return (retval<0?PAM_IGNORE:PAM_SUCCESS); -} - -/* - * This is where we read a line of the PAM config file. The line may be - * preceeded by lines of comments and also extended with "\\\n" - */ - -static int _assemble_line(FILE *f, char *buffer, int buf_len) -{ - char *p = buffer; - char *s, *os; - int used = 0; - - /* loop broken with a 'break' when a non-'\\n' ended line is read */ - - D(("called.")); - for (;;) { - if (used >= buf_len) { - /* Overflow */ - D(("_assemble_line: overflow")); - return -1; - } - if (fgets(p, buf_len - used, f) == NULL) { - if (used) { - /* Incomplete read */ - return -1; - } else { - /* EOF */ - return 0; - } - } - - /* skip leading spaces --- line may be blank */ - - s = p + strspn(p, " \n\t"); - if (*s && (*s != '#')) { - os = s; - - /* - * we are only interested in characters before the first '#' - * character - */ - - while (*s && *s != '#') - ++s; - if (*s == '#') { - *s = '\0'; - used += strlen(os); - break; /* the line has been read */ - } - - s = os; - - /* - * Check for backslash by scanning back from the end of - * the entered line, the '\n' has been included since - * normally a line is terminated with this - * character. fgets() should only return one though! - */ - - s += strlen(s); - while (s > os && ((*--s == ' ') || (*s == '\t') - || (*s == '\n'))); - - /* check if it ends with a backslash */ - if (*s == '\\') { - *s = '\0'; /* truncate the line here */ - used += strlen(os); - p = s; /* there is more ... */ - } else { - /* End of the line! */ - used += strlen(os); - break; /* this is the complete line */ - } - - } else { - /* Nothing in this line */ - /* Don't move p */ - } - } - - return used; -} - -static int _parse_line(char *buffer, VAR *var) -{ - /* - * parse buffer into var, legal syntax is - * VARIABLE [DEFAULT=[[string]] [OVERRIDE=[value]] - * - * Any other options defined make this a bad line, - * error logged and no var set - */ - - int length, quoteflg=0; - char *ptr, **valptr, *tmpptr; - - D(("Called buffer = <%s>", buffer)); - - length = strcspn(buffer," \t\n"); - - if ((var->name = malloc(length + 1)) == NULL) { - _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1); - return PAM_BUF_ERR; - } - - /* - * The first thing on the line HAS to be the variable name, - * it may be the only thing though. - */ - strncpy(var->name, buffer, length); - var->name[length] = '\0'; - D(("var->name = <%s>, length = %d", var->name, length)); - - /* - * Now we check for arguments, we only support two kinds and ('cause I am lazy) - * each one can actually be listed any number of times - */ - - ptr = buffer+length; - while ((length = strspn(ptr, " \t")) > 0) { - ptr += length; /* remove leading whitespace */ - D((ptr)); - if (strncmp(ptr,"DEFAULT=",8) == 0) { - ptr+=8; - D(("Default arg found: <%s>", ptr)); - valptr=&(var->defval); - } else if (strncmp(ptr, "OVERRIDE=", 9) == 0) { - ptr+=9; - D(("Override arg found: <%s>", ptr)); - valptr=&(var->override); - } else { - D(("Unrecognized options: <%s> - ignoring line", ptr)); - _log_err(LOG_ERR, "Unrecognized Option: %s - ignoring line", ptr); - return BAD_LINE; - } - - if ('"' != *ptr) { /* Escaped quotes not supported */ - length = strcspn(ptr, " \t\n"); - tmpptr = ptr+length; - } else { - tmpptr = strchr(++ptr, '"'); - if (!tmpptr) { - D(("Unterminated quoted string: %s", ptr-1)); - _log_err(LOG_ERR, "Unterminated quoted string: %s", ptr-1); - return BAD_LINE; - } - length = tmpptr - ptr; - if (*++tmpptr && ' ' != *tmpptr && '\t' != *tmpptr && '\n' != *tmpptr) { - D(("Quotes must cover the entire string: <%s>", ptr)); - _log_err(LOG_ERR, "Quotes must cover the entire string: <%s>", ptr); - return BAD_LINE; - } - quoteflg++; - } - if (length) { - if ((*valptr = malloc(length + 1)) == NULL) { - D(("Couldn't malloc %d bytes", length+1)); - _log_err(LOG_ERR, "Couldn't malloc %d bytes", length+1); - return PAM_BUF_ERR; - } - (void)strncpy(*valptr,ptr,length); - (*valptr)[length]='\0'; - } else if (quoteflg--) { - *valptr = "e; /* a quick hack to handle the empty string */ - } - ptr = tmpptr; /* Start the search where we stopped */ - } /* while */ - - /* - * The line is parsed, all is well. - */ - - D(("Exit.")); - ptr = NULL; tmpptr = NULL; valptr = NULL; - return GOOD_LINE; -} - -static int _check_var(pam_handle_t *pamh, VAR *var) -{ - /* - * Examine the variable and determine what action to take. - * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take - * or a PAM_* error code if passed back from other routines - * - * if no DEFAULT provided, the empty string is assumed - * if no OVERRIDE provided, the empty string is assumed - * if DEFAULT= and OVERRIDE evaluates to the empty string, - * this variable should be undefined - * if DEFAULT="" and OVERRIDE evaluates to the empty string, - * this variable should be defined with no value - * if OVERRIDE=value and value turns into the empty string, DEFAULT is used - * - * If DEFINE_VAR is to be returned, the correct value to define will - * be pointed to by var->value - */ - - int retval; - - D(("Called.")); - - /* - * First thing to do is to expand any arguments, but only - * if they are not the special quote values (cause expand_arg - * changes memory). - */ - - if (var->defval && ("e != var->defval) && - ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { - return retval; - } - if (var->override && ("e != var->override) && - ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { - return retval; - } - - /* Now its easy */ - - if (var->override && *(var->override) && "e != var->override) { - /* if there is a non-empty string in var->override, we use it */ - D(("OVERRIDE variable <%s> being used: <%s>", var->name, var->override)); - var->value = var->override; - retval = DEFINE_VAR; - } else { - - var->value = var->defval; - if ("e == var->defval) { - /* - * This means that the empty string was given for defval value - * which indicates that a variable should be defined with no value - */ - *var->defval = '\0'; - D(("An empty variable: <%s>", var->name)); - retval = DEFINE_VAR; - } else if (var->defval) { - D(("DEFAULT variable <%s> being used: <%s>", var->name, var->defval)); - retval = DEFINE_VAR; - } else { - D(("UNDEFINE variable <%s>", var->name)); - retval = UNDEFINE_VAR; - } - } - - D(("Exit.")); - return retval; -} - -static int _expand_arg(pam_handle_t *pamh, char **value) -{ - const char *orig=*value, *tmpptr=NULL; - char *ptr; /* - * Sure would be nice to use tmpptr but it needs to be - * a constant so that the compiler will shut up when I - * call pam_getenv and _pam_get_item_byname -- sigh - */ - - /* No unexpanded variable can be bigger than BUF_SIZE */ - char type, tmpval[BUF_SIZE]; - - /* I know this shouldn't be hard-coded but it's so much easier this way */ - char tmp[MAX_ENV]; - - D(("Remember to initialize tmp!")); - memset(tmp, 0, MAX_ENV); - - /* - * (possibly non-existent) environment variables can be used as values - * by prepending a "$" and wrapping in {} (ie: ${HOST}), can escape with "\" - * (possibly non-existent) PAM items can be used as values - * by prepending a "@" and wrapping in {} (ie: @{PAM_RHOST}, can escape - * - */ - D(("Expanding <%s>",orig)); - while (*orig) { /* while there is some input to deal with */ - if ('\\' == *orig) { - ++orig; - if ('$' != *orig && '@' != *orig) { - D(("Unrecognized escaped character: <%c> - ignoring", *orig)); - _log_err(LOG_ERR, "Unrecognized escaped character: <%c> - ignoring", - *orig); - } else if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ - } else { - /* is it really a good idea to try to log this? */ - D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); - _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", - tmp, tmpptr); - } - continue; - } - if ('$' == *orig || '@' == *orig) { - if ('{' != *(orig+1)) { - D(("Expandable variables must be wrapped in {}" - " <%s> - ignoring", orig)); - _log_err(LOG_ERR, "Expandable variables must be wrapped in {}" - " <%s> - ignoring", orig); - if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ - } - continue; - } else { - D(("Expandable argument: <%s>", orig)); - type = *orig; - orig+=2; /* skip the ${ or @{ characters */ - ptr = strchr(orig, '}'); - if (ptr) { - *ptr++ = '\0'; - } else { - D(("Unterminated expandable variable: <%s>", orig-2)); - _log_err(LOG_ERR, "Unterminated expandable variable: <%s>", orig-2); - return PAM_ABORT; - } - strncpy(tmpval, orig, sizeof(tmpval)); - tmpval[sizeof(tmpval)-1] = '\0'; - orig=ptr; - /* - * so, we know we need to expand tmpval, it is either - * an environment variable or a PAM_ITEM. type will tell us which - */ - switch (type) { - - case '$': - D(("Expanding env var: <%s>",tmpval)); - tmpptr = pam_getenv(pamh, tmpval); - D(("Expanded to <%s>", tmpptr)); - break; - - case '@': - D(("Expanding pam item: <%s>",tmpval)); - tmpptr = _pam_get_item_byname(pamh, tmpval); - D(("Expanded to <%s>", tmpptr)); - break; - - default: - D(("Impossible error, type == <%c>", type)); - _log_err(LOG_CRIT, "Impossible error, type == <%c>", type); - return PAM_ABORT; - } /* switch */ - - if (tmpptr) { - if ((strlen(tmp) + strlen(tmpptr)) < MAX_ENV) { - strcat(tmp, tmpptr); - } else { - /* is it really a good idea to try to log this? */ - D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); - _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); - } - } - } /* if ('{' != *orig++) */ - } else { /* if ( '$' == *orig || '@' == *orig) */ - if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ - } else { - /* is it really a good idea to try to log this? */ - D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); - _log_err(LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); - } - } - } /* for (;*orig;) */ - - if (strlen(tmp) > strlen(*value)) { - free(*value); - if ((*value = malloc(strlen(tmp) +1)) == NULL) { - D(("Couldn't malloc %d bytes for expanded var", strlen(tmp)+1)); - _log_err(LOG_ERR,"Couldn't malloc %d bytes for expanded var", - strlen(tmp)+1); - return PAM_BUF_ERR; - } - } - strcpy(*value, tmp); - memset(tmp,'\0',sizeof(tmp)); - D(("Exit.")); - - return PAM_SUCCESS; -} - -static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) -{ - /* - * This function just allows me to use names as given in the config - * file and translate them into the appropriate PAM_ITEM macro - */ - - int item; - const char *itemval; - - D(("Called.")); - if (strcmp(name, "PAM_USER") == 0) { - item = PAM_USER; - } else if (strcmp(name, "PAM_USER_PROMPT") == 0) { - item = PAM_USER_PROMPT; - } else if (strcmp(name, "PAM_TTY") == 0) { - item = PAM_TTY; - } else if (strcmp(name, "PAM_RUSER") == 0) { - item = PAM_RUSER; - } else if (strcmp(name, "PAM_RHOST") == 0) { - item = PAM_RHOST; - } else { - D(("Unknown PAM_ITEM: <%s>", name)); - _log_err(LOG_ERR, "Unknown PAM_ITEM: <%s>", name); - return NULL; - } - - if (pam_get_item(pamh, item, (const void **)&itemval) != PAM_SUCCESS) { - D(("pam_get_item failed")); - return NULL; /* let pam_get_item() log the error */ - } - D(("Exit.")); - return itemval; -} - -static int _define_var(pam_handle_t *pamh, VAR *var) -{ - /* We have a variable to define, this is a simple function */ - - char *envvar; - int size, retval=PAM_SUCCESS; - - D(("Called.")); - size = strlen(var->name)+strlen(var->value)+2; - if ((envvar = malloc(size)) == NULL) { - D(("Malloc fail, size = %d", size)); - _log_err(LOG_ERR, "Malloc fail, size = %d", size); - return PAM_BUF_ERR; - } - (void) sprintf(envvar,"%s=%s",var->name,var->value); - retval = pam_putenv(pamh, envvar); - free(envvar); envvar=NULL; - D(("Exit.")); - return retval; -} - -static int _undefine_var(pam_handle_t *pamh, VAR *var) -{ - /* We have a variable to undefine, this is a simple function */ - - D(("Called and exit.")); - return pam_putenv(pamh, var->name); -} - -static void _clean_var(VAR *var) -{ - if (var->name) { - free(var->name); - } - if (var->defval && ("e != var->defval)) { - free(var->defval); - } - if (var->override && ("e != var->override)) { - free(var->override); - } - var->name = NULL; - var->value = NULL; /* never has memory specific to it */ - var->defval = NULL; - var->override = NULL; - return; -} - - - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return PAM_IGNORE; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; - char *conf_file=NULL, *env_file=NULL; - - /* - * this module sets environment variables read in from a file - */ - - D(("Called.")); - ctrl = _pam_parse(flags, argc, argv, &conf_file, &env_file, &readenv); - - retval = _parse_config_file(pamh, ctrl, &conf_file); - - if(readenv) - _parse_env_file(pamh, ctrl, &env_file); - - /* indicate success or failure */ - - D(("Exit.")); - return retval; -} - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - _log_err(LOG_NOTICE, "pam_sm_acct_mgmt called inappropriatly"); - return PAM_SERVICE_ERR; -} - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; - char *conf_file=NULL, *env_file=NULL; - - /* - * this module sets environment variables read in from a file - */ - - D(("Called.")); - ctrl = _pam_parse(flags, argc, argv, &conf_file, &env_file, &readenv); - - retval = _parse_config_file(pamh, ctrl, &conf_file); - - if(readenv) - _parse_env_file(pamh, ctrl, &env_file); - - /* indicate success or failure */ - - D(("Exit.")); - return retval; -} - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc, - const char **argv) -{ - D(("Called and Exit")); - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - _log_err(LOG_NOTICE, "pam_sm_chauthtok called inappropriatly"); - return PAM_SERVICE_ERR; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_env_modstruct = { - "pam_env", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_env/pam_env.conf-example b/modules/pam_env/pam_env.conf-example deleted file mode 100644 index c2c4333f..00000000 --- a/modules/pam_env/pam_env.conf-example +++ /dev/null @@ -1,72 +0,0 @@ -# $Date$ -# $Author$ -# $Id$ -# -# This is the configuration file for pam_env, a PAM module to load in -# a configurable list of environment variables for a -# -# The original idea for this came from Andrew G. Morgan ... -#<quote> -# Mmm. Perhaps you might like to write a pam_env module that reads a -# default environment from a file? I can see that as REALLY -# useful... Note it would be an "auth" module that returns PAM_IGNORE -# for the auth part and sets the environment returning PAM_SUCCESS in -# the setcred function... -#</quote> -# -# What I wanted was the REMOTEHOST variable set, purely for selfish -# reasons, and AGM didn't want it added to the SimpleApps login -# program (which is where I added the patch). So, my first concern is -# that variable, from there there are numerous others that might/would -# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER ..... -# -# Of course, these are a different kind of variable than REMOTEHOST in -# that they are things that are likely to be configured by -# administrators rather than set by logging in, how to treat them both -# in the same config file? -# -# Here is my idea: -# -# Each line starts with the variable name, there are then two possible -# options for each variable DEFAULT and OVERRIDE. -# DEFAULT allows and administrator to set the value of the -# variable to some default value, if none is supplied then the empty -# string is assumed. The OVERRIDE option tells pam_env that it should -# enter in its value (overriding the default value) if there is one -# to use. OVERRIDE is not used, "" is assumed and no override will be -# done. -# -# VARIABLE [DEFAULT=[value]] [OVERRIDE=[value]] -# -# (Possibly non-existent) environment variables may be used in values -# using the ${string} syntax and (possibly non-existent) PAM_ITEMs may -# be used in values using the @{string} syntax. Both the $ and @ -# characters can be backslash escaped to be used as literal values -# values can be delimited with "", escaped " not supported. -# -# -# First, some special variables -# -# Set the REMOTEHOST variable for any hosts that are remote, default -# to "localhost" rather than not being set at all -#REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST} -# -# Set the DISPLAY variable if it seems reasonable -#DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY} -# -# -# Now some simple variables -# -#PAGER DEFAULT=less -#MANPAGER DEFAULT=less -#LESS DEFAULT="M q e h15 z23 b80" -#NNTPSERVER DEFAULT=localhost -#PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\ -#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11 -# -# silly examples of escaped variables, just to show how they work. -# -#DOLLAR DEFAULT=\$ -#DOLLARDOLLAR DEFAULT= OVERRIDE=\$${DOLLAR} -#DOLLARPLUS DEFAULT=\${REMOTEHOST}${REMOTEHOST} -#ATSIGN DEFAULT="" OVERRIDE=\@ diff --git a/modules/pam_filter/.cvsignore b/modules/pam_filter/.cvsignore deleted file mode 100644 index 877dafe0..00000000 --- a/modules/pam_filter/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -dynamic -security diff --git a/modules/pam_filter/.upperLOWER b/modules/pam_filter/.upperLOWER deleted file mode 100644 index 2531b468..00000000 --- a/modules/pam_filter/.upperLOWER +++ /dev/null @@ -1 +0,0 @@ -a test filter that transposes upper and lower case characters diff --git a/modules/pam_filter/Makefile b/modules/pam_filter/Makefile deleted file mode 100644 index 48411497..00000000 --- a/modules/pam_filter/Makefile +++ /dev/null @@ -1,126 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 -# - -ifeq ($(OS),solaris) - -include ../dont_makefile - -else - -include ../../Make.Rules - -TITLE=pam_filter -FILTERS=upperLOWER -FILTERSDIR=$(SECUREDIR)/pam_filter -export FILTERSDIR - -CFLAGS += -Iinclude - -LIBSRC = $(TITLE).c -LIBOBJ = $(TITLE).o -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -LIBOBJS = $(addprefix static/,$(LIBOBJ)) - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -ifdef DYNAMIC -LIBSHARED = $(TITLE).so -endif - -ifdef STATIC -LIBSTATIC = lib$(TITLE).o -endif - -####################### don't edit below ####################### - -# -# this is where we compile this module -# - -all: dirs $(LIBSHARED) $(LIBSTATIC) register filters - -dirs: - if [ ! -r include/security ]; then ln -sf . include/security ; fi -ifdef DYNAMIC - $(MKDIR) ./dynamic -endif -ifdef STATIC - $(MKDIR) ./static -endif - -register: -ifdef STATIC - ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) -endif - -filters: - @for i in $(FILTERS) ; do \ - if [ -d $$i ]; then \ - $(MAKE) -C $$i all ; \ - fi ; \ - done - - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) -endif - -ifdef DYNAMIC -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) -endif - -ifdef STATIC -$(LIBOBJS): $(LIBSRC) -endif - -ifdef STATIC -$(LIBSTATIC): $(LIBOBJS) - $(LD) -r -o $@ $(LIBOBJS) -endif - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so - rm -f $(FAKEROOT)$(INCLUDED)/pam_filter.h - @for i in $(FILTERS) ; do \ - if [ -d $$i ]; then \ - $(MAKE) -C $$i remove ; \ - fi ; \ - done - -install: all - @for i in $(FILTERS) ; do \ - if [ -d $$i ]; then \ - $(MAKE) -C $$i install ; \ - fi ; \ - done - $(MKDIR) $(FAKEROOT)$(SECUREDIR) -ifdef DYNAMIC - $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) -endif - $(MKDIR) $(FAKEROOT)$(INCLUDED) - $(INSTALL) -m 644 include/pam_filter.h $(FAKEROOT)$(INCLUDED) - -clean: - @for i in $(FILTERS) ; do \ - if [ -d $$i ]; then \ - $(MAKE) -C $$i clean ; \ - fi ; \ - done - rm -f $(LIBSHARED) $(LIBOBJD) $(LIBOBJS) core *~ - rm -f include/security - rm -fr dynamic static - rm -f *.a *.o *.so *.bak - -endif diff --git a/modules/pam_filter/README b/modules/pam_filter/README deleted file mode 100644 index 850f1145..00000000 --- a/modules/pam_filter/README +++ /dev/null @@ -1,94 +0,0 @@ -# -# $Id$ -# -# This describes the behavior of this module with respect to the -# /etc/pam.conf file. -# -# writen by Andrew Morgan <morgan@parc.power.net> -# - -This module is intended to be a platform for providing access to all -of the input/output that passes between the user and the application. -It is only suitable for tty-based and (stdin/stdout) applications. And -is only known to work on Linux based systems. - -The action of the module is dictated by the arguments it is given in -the pam.conf file. - -recognized flags are: - - debug print some information to syslog(3) - - new_term set the PAM_TTY item to the new filtered - terminal (the default is to set it - to be that of the users terminal) - - non_term don't try to set the PAM_TTY item - - run1/run2 these arguments indicate that the - module should separate the application - from the user and insert a filter - program between them. The pathname of - the filter program follows the 'runN' - argument. Arguments that follow this - pathname are passed as arguments to - the filter program. - - The distinction between run1 and run2 - is which of the two functions of - the given management-type triggers the - execution of the indicated filter. - - type: run1 run2 - ----- ---- ---- - - auth pam_sm_authenticate pam_sm_setcred - - account [ pam_sm_acct_mgmt (either is good) ] - - session pam_sm_open_session pam_sm_close_session - - password pam_sm_chauthtok/PRELIM pam_sm_chauthtok/UPDATE - -Note, in the case of 'password' PRELIM/UPDATE indicates which of the -two calls to pam_sm_chauthtok from libpam (not the application) will -trigger the filter. - -What a filter program should expect: ------------------------------------- - -Definitions for filter programs (which may be locally designed) are -contained in the <security/pam_filter.h> file. - -Arguments are not passed to the filter on the command line, since this -is plainly visible when a user types 'ps -a'. Instead they are passed -as the filter's environment. Other information is passed in this way -too. - -Here is a list of the environment variables that a filter should -expect: - - ARGS="filter_path_name argument list" - SERVICE="service_name" (as it appears in /etc/pam.conf) - USER="username" - TYPE="module_fn" (the name of the function in pam_filter.so - that invoked the filter) - -[This list is likely to grow. If you want something added, email me!] - -Among other things this module is intended to provide a useful means -of logging the activity of users in as discrete a manner as possible. - -Existing filters: ------------------ - -Currently, there is a single supplied filter (upperLOWER). The effect -of using this filter is to transpose upper and lower case letters -between the user and the application. This is really annoying when you -try the 'xsh' example application! ;) - -TODO: provide more filters... - Decide if providing stderr interception is really overkill. - -Andrew G. Morgan <morgan@parc.power.net> 1996/5/27 - diff --git a/modules/pam_filter/include/pam_filter.h b/modules/pam_filter/include/pam_filter.h deleted file mode 100644 index 630198ee..00000000 --- a/modules/pam_filter/include/pam_filter.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * $Id$ - * - * this file is associated with the Linux-PAM filter module. - * it was written by Andrew G. Morgan <morgan@linux.kernel.org> - * - */ - -#ifndef PAM_FILTER_H -#define PAM_FILTER_H - -#include <sys/file.h> - -/* - * this will fail if there is some problem with these file descriptors - * being allocated by the pam_filter Linux-PAM module. The numbers - * here are thought safe, but the filter developer should use the - * macros, as these numbers are subject to change. - * - * The APPXXX_FILENO file descriptors are the STDIN/OUT/ERR_FILENO of the - * application. The filter uses the STDIN/OUT/ERR_FILENO's to converse - * with the user, passes (modified) user input to the application via - * APPIN_FILENO, and receives application output from APPOUT_FILENO/ERR. - */ - -#define APPIN_FILENO 3 /* write here to give application input */ -#define APPOUT_FILENO 4 /* read here to get application output */ -#define APPERR_FILENO 5 /* read here to get application errors */ - -#define APPTOP_FILE 6 /* used by select */ - -#endif diff --git a/modules/pam_filter/pam_filter.c b/modules/pam_filter/pam_filter.c deleted file mode 100644 index 9a6fc8c5..00000000 --- a/modules/pam_filter/pam_filter.c +++ /dev/null @@ -1,735 +0,0 @@ -/* - * $Id$ - * - * written by Andrew Morgan <morgan@transmeta.com> with much help from - * Richard Stevens' UNIX Network Programming book. - */ - -#include <security/_pam_aconf.h> - -#include <stdlib.h> -#include <syslog.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include <stdio.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/time.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <termio.h> - -#include <signal.h> - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> -#include <security/pam_filter.h> - -/* ------ some tokens used for convenience throughout this file ------- */ - -#define FILTER_DEBUG 01 -#define FILTER_RUN1 02 -#define FILTER_RUN2 04 -#define NEW_TERM 010 -#define NON_TERM 020 - -/* -------------------------------------------------------------------- */ - -/* log errors */ - -#include <stdarg.h> - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("pam_filter", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -#define TERMINAL_LEN 12 - -static int master(char *terminal) -/* - * try to open all of the terminals in sequence return first free one, - * or -1 - */ -{ - const char ptys[] = "pqrs", *pty = ptys; - const char hexs[] = "0123456789abcdef", *hex; - struct stat tstat; - int fd; - - strcpy(terminal, "/dev/pty??"); - - while (*pty) { /* step through four types */ - terminal[8] = *pty++; - terminal[9] = '0'; - if (stat(terminal,&tstat) < 0) { - _pam_log(LOG_WARNING, "unknown pseudo terminal; %s", terminal); - break; - } - for (hex = hexs; *hex; ) { /* step through 16 of these */ - terminal[9] = *hex++; - if ((fd = open(terminal, O_RDWR)) >= 0) { - return fd; - } - } - } - - /* no terminal found */ - - return -1; -} - -static int process_args(pam_handle_t *pamh - , int argc, const char **argv, const char *type - , char ***evp, const char **filtername) -{ - int ctrl=0; - - while (argc-- > 0) { - if (strcmp("debug",*argv) == 0) { - ctrl |= FILTER_DEBUG; - } else if (strcmp("new_term",*argv) == 0) { - ctrl |= NEW_TERM; - } else if (strcmp("non_term",*argv) == 0) { - ctrl |= NON_TERM; - } else if (strcmp("run1",*argv) == 0) { - ctrl |= FILTER_RUN1; - if (argc <= 0) { - _pam_log(LOG_ALERT,"no run filter supplied"); - } else - break; - } else if (strcmp("run2",*argv) == 0) { - ctrl |= FILTER_RUN2; - if (argc <= 0) { - _pam_log(LOG_ALERT,"no run filter supplied"); - } else - break; - } else { - _pam_log(LOG_ERR, "unrecognized option: %s (ignored)", *argv); - } - ++argv; /* step along list */ - } - - if (argc < 0) { - /* there was no reference to a filter */ - *filtername = NULL; - *evp = NULL; - } else { - char **levp; - const char *tmp; - int i,size; - - *filtername = *++argv; - if (ctrl & FILTER_DEBUG) { - _pam_log(LOG_DEBUG,"will run filter %s\n", *filtername); - } - - levp = (char **) malloc(5*sizeof(char *)); - if (levp == NULL) { - _pam_log(LOG_CRIT,"no memory for environment of filter"); - return -1; - } - - for (size=i=0; i<argc; ++i) { - size += strlen(argv[i])+1; - } - - /* the "ARGS" variable */ - -#define ARGS_OFFSET 5 /* sizeof('ARGS='); */ -#define ARGS_NAME "ARGS=" - - size += ARGS_OFFSET; - - levp[0] = (char *) malloc(size); - if (levp[0] == NULL) { - _pam_log(LOG_CRIT,"no memory for filter arguments"); - if (levp) { - free(levp); - } - return -1; - } - - strncpy(levp[0],ARGS_NAME,ARGS_OFFSET); - for (i=0,size=ARGS_OFFSET; i<argc; ++i) { - strcpy(levp[0]+size, argv[i]); - size += strlen(argv[i]); - levp[0][size++] = ' '; - } - levp[0][--size] = '\0'; /* <NUL> terminate */ - - /* the "SERVICE" variable */ - -#define SERVICE_OFFSET 8 /* sizeof('SERVICE='); */ -#define SERVICE_NAME "SERVICE=" - - pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp); - size = SERVICE_OFFSET+strlen(tmp); - - levp[1] = (char *) malloc(size+1); - if (levp[1] == NULL) { - _pam_log(LOG_CRIT,"no memory for service name"); - if (levp) { - free(levp[0]); - free(levp); - } - return -1; - } - - strncpy(levp[1],SERVICE_NAME,SERVICE_OFFSET); - strcpy(levp[1]+SERVICE_OFFSET, tmp); - levp[1][size] = '\0'; /* <NUL> terminate */ - - /* the "USER" variable */ - -#define USER_OFFSET 5 /* sizeof('USER='); */ -#define USER_NAME "USER=" - - pam_get_user(pamh, &tmp, NULL); - if (tmp == NULL) { - tmp = "<unknown>"; - } - size = USER_OFFSET+strlen(tmp); - - levp[2] = (char *) malloc(size+1); - if (levp[2] == NULL) { - _pam_log(LOG_CRIT,"no memory for user's name"); - if (levp) { - free(levp[1]); - free(levp[0]); - free(levp); - } - return -1; - } - - strncpy(levp[2],USER_NAME,USER_OFFSET); - strcpy(levp[2]+USER_OFFSET, tmp); - levp[2][size] = '\0'; /* <NUL> terminate */ - - /* the "USER" variable */ - -#define TYPE_OFFSET 5 /* sizeof('TYPE='); */ -#define TYPE_NAME "TYPE=" - - size = TYPE_OFFSET+strlen(type); - - levp[3] = (char *) malloc(size+1); - if (levp[3] == NULL) { - _pam_log(LOG_CRIT,"no memory for type"); - if (levp) { - free(levp[2]); - free(levp[1]); - free(levp[0]); - free(levp); - } - return -1; - } - - strncpy(levp[3],TYPE_NAME,TYPE_OFFSET); - strcpy(levp[3]+TYPE_OFFSET, type); - levp[3][size] = '\0'; /* <NUL> terminate */ - - levp[4] = NULL; /* end list */ - - *evp = levp; - } - - if ((ctrl & FILTER_DEBUG) && *filtername) { - char **e; - - _pam_log(LOG_DEBUG,"filter[%s]: %s",type,*filtername); - _pam_log(LOG_DEBUG,"environment:"); - for (e=*evp; e && *e; ++e) { - _pam_log(LOG_DEBUG," %s",*e); - } - } - - return ctrl; -} - -static void free_evp(char *evp[]) -{ - int i; - - if (evp) - for (i=0; i<4; ++i) { - if (evp[i]) - free(evp[i]); - } - free(evp); -} - -static int set_filter(pam_handle_t *pamh, int flags, int ctrl - , const char **evp, const char *filtername) -{ - int status=-1; - char terminal[TERMINAL_LEN]; - struct termio stored_mode; /* initial terminal mode settings */ - int fd[2], child=0, child2=0, aterminal; - - if (filtername == NULL || *filtername != '/') { - _pam_log(LOG_ALERT, "filtername not permitted; require full path"); - return PAM_ABORT; - } - - if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) { - aterminal = 0; - } else { - aterminal = 1; - } - - if (aterminal) { - - /* open the master pseudo terminal */ - - fd[0] = master(terminal); - if (fd[0] < 0) { - _pam_log(LOG_CRIT,"no master terminal"); - return PAM_AUTH_ERR; - } - - /* set terminal into raw mode.. remember old mode so that we can - revert to it after the child has quit. */ - - /* this is termio terminal handling... */ - - if (ioctl(STDIN_FILENO, TCGETA, (char *) &stored_mode ) < 0) { - /* in trouble, so close down */ - close(fd[0]); - _pam_log(LOG_CRIT, "couldn't copy terminal mode"); - return PAM_ABORT; - } else { - struct termio t_mode = stored_mode; - - t_mode.c_iflag = 0; /* no input control */ - t_mode.c_oflag &= ~OPOST; /* no ouput post processing */ - - /* no signals, canonical input, echoing, upper/lower output */ - t_mode.c_lflag &= ~(ISIG|ICANON|ECHO|XCASE); - t_mode.c_cflag &= ~(CSIZE|PARENB); /* no parity */ - t_mode.c_cflag |= CS8; /* 8 bit chars */ - - t_mode.c_cc[VMIN] = 1; /* number of chars to satisfy a read */ - t_mode.c_cc[VTIME] = 0; /* 0/10th second for chars */ - - if (ioctl(STDIN_FILENO, TCSETA, (char *) &t_mode) < 0) { - close(fd[0]); - _pam_log(LOG_WARNING, "couldn't put terminal in RAW mode"); - return PAM_ABORT; - } - - /* - * NOTE: Unlike the stream socket case here the child - * opens the slave terminal as fd[1] *after* the fork... - */ - } - } else { - - /* - * not a terminal line so just open a stream socket fd[0-1] - * both set... - */ - - if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { - _pam_log(LOG_CRIT,"couldn't open a stream pipe"); - return PAM_ABORT; - } - } - - /* start child process */ - - if ( (child = fork()) < 0 ) { - - _pam_log(LOG_WARNING,"first fork failed"); - if (aterminal) { - (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); - } - - return PAM_AUTH_ERR; - } - - if ( child == 0 ) { /* child process *is* application */ - - if (aterminal) { - - /* close the controlling tty */ - -#if defined(__hpux) && defined(O_NOCTTY) - int t = open("/dev/tty", O_RDWR|O_NOCTTY); -#else - int t = open("/dev/tty",O_RDWR); - if (t > 0) { - (void) ioctl(t, TIOCNOTTY, NULL); - close(t); - } -#endif /* defined(__hpux) && defined(O_NOCTTY) */ - - /* make this process it's own process leader */ - if (setsid() == -1) { - _pam_log(LOG_WARNING,"child cannot become new session"); - return PAM_ABORT; - } - - /* find slave's name */ - terminal[5] = 't'; /* want to open slave terminal */ - fd[1] = open(terminal, O_RDWR); - close(fd[0]); /* process is the child -- uses line fd[1] */ - - if (fd[1] < 0) { - _pam_log(LOG_WARNING,"cannot open slave terminal; %s" - ,terminal); - return PAM_ABORT; - } - - /* initialize the child's terminal to be the way the - parent's was before we set it into RAW mode */ - - if (ioctl(fd[1], TCSETA, (char *) &stored_mode) < 0) { - _pam_log(LOG_WARNING,"cannot set slave terminal mode; %s" - ,terminal); - close(fd[1]); - return PAM_ABORT; - } - - } else { - - /* nothing to do for a simple stream socket */ - - } - - /* re-assign the stdin/out to fd[1] <- (talks to filter). */ - - if ( dup2(fd[1],STDIN_FILENO) != STDIN_FILENO || - dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO || - dup2(fd[1],STDERR_FILENO) != STDERR_FILENO ) { - _pam_log(LOG_WARNING - ,"unable to re-assign STDIN/OUT/ERR...'s"); - close(fd[1]); - return PAM_ABORT; - } - - /* make sure that file descriptors survive 'exec's */ - - if ( fcntl(STDIN_FILENO, F_SETFD, 0) || - fcntl(STDOUT_FILENO,F_SETFD, 0) || - fcntl(STDERR_FILENO,F_SETFD, 0) ) { - _pam_log(LOG_WARNING - ,"unable to re-assign STDIN/OUT/ERR...'s"); - return PAM_ABORT; - } - - /* now the user input is read from the parent/filter: forget fd */ - - close(fd[1]); - - /* the current process is now aparently working with filtered - stdio/stdout/stderr --- success! */ - - return PAM_SUCCESS; - } - - /* - * process is the parent here. So we can close the application's - * input/output - */ - - close(fd[1]); - - /* Clear out passwords... there is a security problem here in - * that this process never executes pam_end. Consequently, any - * other sensitive data in this process is *not* explicitly - * overwritten, before the process terminates */ - - (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); - (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); - - /* fork a copy of process to run the actual filter executable */ - - if ( (child2 = fork()) < 0 ) { - - _pam_log(LOG_WARNING,"filter fork failed"); - child2 = 0; - - } else if ( child2 == 0 ) { /* exec the child filter */ - - if ( dup2(fd[0],APPIN_FILENO) != APPIN_FILENO || - dup2(fd[0],APPOUT_FILENO) != APPOUT_FILENO || - dup2(fd[0],APPERR_FILENO) != APPERR_FILENO ) { - _pam_log(LOG_WARNING - ,"unable to re-assign APPIN/OUT/ERR...'s"); - close(fd[0]); - exit(1); - } - - /* make sure that file descriptors survive 'exec's */ - - if ( fcntl(APPIN_FILENO, F_SETFD, 0) == -1 || - fcntl(APPOUT_FILENO,F_SETFD, 0) == -1 || - fcntl(APPERR_FILENO,F_SETFD, 0) == -1 ) { - _pam_log(LOG_WARNING - ,"unable to retain APPIN/OUT/ERR...'s"); - close(APPIN_FILENO); - close(APPOUT_FILENO); - close(APPERR_FILENO); - exit(1); - } - - /* now the user input is read from the parent through filter */ - - execle(filtername, "<pam_filter>", NULL, evp); - - /* getting to here is an error */ - - _pam_log(LOG_ALERT, "filter: %s, not executable", filtername); - - } else { /* wait for either of the two children to exit */ - - while (child && child2) { /* loop if there are two children */ - int lstatus=0; - int chid; - - chid = wait(&lstatus); - if (chid == child) { - - if (WIFEXITED(lstatus)) { /* exited ? */ - status = WEXITSTATUS(lstatus); - } else if (WIFSIGNALED(lstatus)) { /* killed ? */ - status = -1; - } else - continue; /* just stopped etc.. */ - child = 0; /* the child has exited */ - - } else if (chid == child2) { - /* - * if the filter has exited. Let the child die - * naturally below - */ - if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus)) - child2 = 0; - } else { - - _pam_log(LOG_ALERT - ,"programming error <chid=%d,lstatus=%x>: " - __FILE__ " line %d" - , lstatus, __LINE__ ); - child = child2 = 0; - status = -1; - - } - } - } - - close(fd[0]); - - /* if there is something running, wait for it to exit */ - - while (child || child2) { - int lstatus=0; - int chid; - - chid = wait(&lstatus); - - if (child && chid == child) { - - if (WIFEXITED(lstatus)) { /* exited ? */ - status = WEXITSTATUS(lstatus); - } else if (WIFSIGNALED(lstatus)) { /* killed ? */ - status = -1; - } else - continue; /* just stopped etc.. */ - child = 0; /* the child has exited */ - - } else if (child2 && chid == child2) { - - if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus)) - child2 = 0; - - } else { - - _pam_log(LOG_ALERT - ,"programming error <chid=%d,lstatus=%x>: " - __FILE__ " line %d" - , lstatus, __LINE__ ); - child = child2 = 0; - status = -1; - - } - } - - if (aterminal) { - /* reset to initial terminal mode */ - (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); - } - - if (ctrl & FILTER_DEBUG) { - _pam_log(LOG_DEBUG,"parent process exited"); /* clock off */ - } - - /* quit the parent process, returning the child's exit status */ - - exit(status); -} - -static int set_the_terminal(pam_handle_t *pamh) -{ - const char *tty; - - if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS - || tty == NULL) { - tty = ttyname(STDIN_FILENO); - if (tty == NULL) { - _pam_log(LOG_ERR, "couldn't get the tty name"); - return PAM_ABORT; - } - if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { - _pam_log(LOG_ERR, "couldn't set tty name"); - return PAM_ABORT; - } - } - return PAM_SUCCESS; -} - -static int need_a_filter(pam_handle_t *pamh - , int flags, int argc, const char **argv - , const char *name, int which_run) -{ - int ctrl; - char **evp; - const char *filterfile; - int retval; - - ctrl = process_args(pamh, argc, argv, name, &evp, &filterfile); - if (ctrl == -1) { - return PAM_AUTHINFO_UNAVAIL; - } - - /* set the tty to the old or the new one? */ - - if (!(ctrl & NON_TERM) && !(ctrl & NEW_TERM)) { - retval = set_the_terminal(pamh); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "tried and failed to set PAM_TTY"); - } - } else { - retval = PAM_SUCCESS; /* nothing to do which is always a success */ - } - - if (retval == PAM_SUCCESS && (ctrl & which_run)) { - retval = set_filter(pamh, flags, ctrl - , (const char **)evp, filterfile); - } - - if (retval == PAM_SUCCESS - && !(ctrl & NON_TERM) && (ctrl & NEW_TERM)) { - retval = set_the_terminal(pamh); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR - , "tried and failed to set new terminal as PAM_TTY"); - } - } - - free_evp(evp); - - if (ctrl & FILTER_DEBUG) { - _pam_log(LOG_DEBUG, "filter/%s, returning %d", name, retval); - _pam_log(LOG_DEBUG, "[%s]", pam_strerror(pamh, retval)); - } - - return retval; -} - -/* ----------------- public functions ---------------- */ - -/* - * here are the advertised access points ... - */ - -/* ------------------ authentication ----------------- */ - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh - , int flags, int argc, const char **argv) -{ - return need_a_filter(pamh, flags, argc, argv - , "authenticate", FILTER_RUN1); -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - return need_a_filter(pamh, flags, argc, argv, "setcred", FILTER_RUN2); -} - -/* --------------- account management ---------------- */ - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return need_a_filter(pamh, flags, argc, argv - , "setcred", FILTER_RUN1|FILTER_RUN2 ); -} - -/* --------------- session management ---------------- */ - -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - return need_a_filter(pamh, flags, argc, argv - , "open_session", FILTER_RUN1); -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - return need_a_filter(pamh, flags, argc, argv - , "close_session", FILTER_RUN2); -} - -/* --------- updating authentication tokens --------- */ - - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - int runN; - - if (flags & PAM_PRELIM_CHECK) - runN = FILTER_RUN1; - else if (flags & PAM_UPDATE_AUTHTOK) - runN = FILTER_RUN2; - else { - _pam_log(LOG_ERR, "unknown flags for chauthtok (0x%X)", flags); - return PAM_TRY_AGAIN; - } - - return need_a_filter(pamh, flags, argc, argv, "chauthtok", runN); -} - -#ifdef PAM_STATIC - -/* ------------ stuff for static modules ------------ */ - -struct pam_module _pam_filter_modstruct = { - "pam_filter", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok, -}; - -#endif diff --git a/modules/pam_filter/upperLOWER/.cvsignore b/modules/pam_filter/upperLOWER/.cvsignore deleted file mode 100644 index bcd63650..00000000 --- a/modules/pam_filter/upperLOWER/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -upperLOWER diff --git a/modules/pam_filter/upperLOWER/Makefile b/modules/pam_filter/upperLOWER/Makefile deleted file mode 100644 index 77bc4102..00000000 --- a/modules/pam_filter/upperLOWER/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# $Id$ -# -# This directory contains a pam_filter filter executable -# -# Created by Andrew Morgan <morgan@transmeta.com> 1996/3/11 -# - -include ../../../Make.Rules - -TITLE=upperLOWER - -# - -CFLAGS += -I../include - -OBJS = $(TITLE).o - -####################### don't edit below ####################### - -all: $(TITLE) - -$(TITLE): $(OBJS) - $(CC) $(CFLAGS) -o $(TITLE) $(OBJS) - $(STRIP) $(TITLE) - -install: - $(MKDIR) $(FAKEROOT)$(FILTERSDIR) - $(INSTALL) -m 511 $(TITLE) $(FAKEROOT)$(FILTERSDIR) - -remove: - cd $(FAKEROOT)$(FILTERSDIR) && rm -f $(TITLE) - -clean: - rm -f $(TITLE) $(OBJS) core *~ - -.c.o: - $(CC) $(CFLAGS) -c $< - diff --git a/modules/pam_filter/upperLOWER/upperLOWER.c b/modules/pam_filter/upperLOWER/upperLOWER.c deleted file mode 100644 index e750e877..00000000 --- a/modules/pam_filter/upperLOWER/upperLOWER.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * $Id$ - * - * This is a sample filter program, for use with pam_filter (a module - * provided with Linux-PAM). This filter simply transposes upper and - * lower case letters, it is intended for demonstration purposes and - * it serves no purpose other than to annoy the user... - */ - -#include <security/_pam_aconf.h> - -#ifdef MEMORY_DEBUG -# undef exit -#endif /* MEMORY_DEBUG */ - -#include <stdio.h> -#include <stdlib.h> -#include <syslog.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> - -#include <security/pam_filter.h> - -/* ---------------------------------------------------------------- */ - -#include <stdarg.h> -#ifdef hpux -# define log_this syslog -#else -static void log_this(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("upperLOWER", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} -#endif - -#include <ctype.h> - -static void do_transpose(char *buffer,int len) -{ - int i; - for (i=0; i<len; ++i) { - if (islower(buffer[i])) { - buffer[i] = toupper(buffer[i]); - } else { - buffer[i] = tolower(buffer[i]); - } - } -} - -extern char **environ; - -int main(int argc, char **argv) -{ - char buffer[BUFSIZ]; - fd_set readers; - void (*before_user)(char *,int); - void (*before_app)(char *,int); - -#ifdef DEBUG - { - int i; - - fprintf(stderr,"environment :[\r\n"); - for (i=0; environ[i]; ++i) { - fprintf(stderr,"-> %s\r\n",environ[i]); - } - fprintf(stderr,"]: end\r\n"); - } -#endif - - if (argc != 1) { -#ifdef DEBUG - fprintf(stderr,"filter invoked as conventional executable\n"); -#else - log_this(LOG_ERR, "filter invoked as conventional executable"); -#endif - exit(1); - } - - before_user = before_app = do_transpose; /* assign filter functions */ - - /* enter a loop that deals with the input and output of the - user.. passing it to and from the application */ - - FD_ZERO(&readers); /* initialize reading mask */ - - for (;;) { - - FD_SET(APPOUT_FILENO, &readers); /* wake for output */ - FD_SET(APPERR_FILENO, &readers); /* wake for error */ - FD_SET(STDIN_FILENO, &readers); /* wake for input */ - - if ( select(APPTOP_FILE,&readers,NULL,NULL,NULL) < 0 ) { -#ifdef DEBUG - fprintf(stderr,"select failed\n"); -#else - log_this(LOG_WARNING,"select failed"); -#endif - break; - } - - /* application errors */ - - if ( FD_ISSET(APPERR_FILENO,&readers) ) { - int got = read(APPERR_FILENO, buffer, BUFSIZ); - if (got <= 0) { - break; - } else { - /* translate to give to real terminal */ - if (before_user != NULL) - before_user(buffer, got); - if ( write(STDERR_FILENO, buffer, got) != got ) { - log_this(LOG_WARNING,"couldn't write %d bytes?!",got); - break; - } - } - } else if ( FD_ISSET(APPOUT_FILENO,&readers) ) { /* app output */ - int got = read(APPOUT_FILENO, buffer, BUFSIZ); - if (got <= 0) { - break; - } else { - /* translate to give to real terminal */ - if (before_user != NULL) - before_user(buffer, got); - if ( write(STDOUT_FILENO, buffer, got) != got ) { - log_this(LOG_WARNING,"couldn't write %d bytes!?",got); - break; - } - } - } - - if ( FD_ISSET(STDIN_FILENO, &readers) ) { /* user input */ - int got = read(STDIN_FILENO, buffer, BUFSIZ); - if (got < 0) { - log_this(LOG_WARNING,"user input junked"); - break; - } else if (got) { - /* translate to give to application */ - if (before_app != NULL) - before_app(buffer, got); - if ( write(APPIN_FILENO, buffer, got) != got ) { - log_this(LOG_WARNING,"couldn't pass %d bytes!?",got); - break; - } - } else { - /* nothing received -- an error? */ - log_this(LOG_WARNING,"user input null?"); - break; - } - } - } - - exit(0); -} - - - diff --git a/modules/pam_ftp/.cvsignore b/modules/pam_ftp/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_ftp/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_ftp/Makefile b/modules/pam_ftp/Makefile deleted file mode 100644 index fb61ac16..00000000 --- a/modules/pam_ftp/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_ftp - -include ../Simple.Rules diff --git a/modules/pam_ftp/README b/modules/pam_ftp/README deleted file mode 100644 index 6d03330c..00000000 --- a/modules/pam_ftp/README +++ /dev/null @@ -1,18 +0,0 @@ -This is the README for pam_ftp ------------------------------- - -This module is an authentication module that does simple ftp -authentication. - -Recognized arguments: - - "debug" print debug messages - "users=" comma separated list of users which - could login only with email adress - "ignore" allow invalid email adresses - -Options for: -auth: for authentication it provides pam_authenticate() and - pam_setcred() hooks. - -Thorsten Kukuk <kukuk@suse.de>, 17. June 1999 diff --git a/modules/pam_ftp/pam_ftp.c b/modules/pam_ftp/pam_ftp.c deleted file mode 100644 index bebcd2b2..00000000 --- a/modules/pam_ftp/pam_ftp.c +++ /dev/null @@ -1,297 +0,0 @@ -/* pam_ftp module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 - * - */ - -#define PLEASE_ENTER_PASSWORD "Password required for %s." -#define GUEST_LOGIN_PROMPT "Guest login ok, " \ -"send your complete e-mail address as password." - -/* the following is a password that "can't be correct" */ -#define BLOCK_PASSWORD "\177BAD PASSWPRD\177" - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <syslog.h> -#include <stdarg.h> -#include <string.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -static int converse(pam_handle_t *pamh, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse\n")); - - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { - - retval = conv->conv(nargs, ( const struct pam_message ** ) message - , response, conv->appdata_ptr); - - D(("returned from application's conversation function\n")); - - if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) { - _pam_log(LOG_DEBUG, "conversation failure [%s]" - , pam_strerror(pamh, retval)); - } - - } else { - _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]" - , pam_strerror(pamh, retval)); - } - - D(("ready to return from module conversation\n")); - - return retval; /* propagate error status */ -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 01 -#define PAM_IGNORE_EMAIL 02 -#define PAM_NO_ANON 04 - -static int _pam_parse(int argc, const char **argv, char **users) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strncmp(*argv,"users=",6)) { - *users = x_strdup(6+*argv); - if (*users == NULL) { - ctrl |= PAM_NO_ANON; - _pam_log(LOG_CRIT, "failed to duplicate user list - anon off"); - } - } else if (!strcmp(*argv,"ignore")) { - ctrl |= PAM_IGNORE_EMAIL; - } else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -/* - * check if name is in list or default list. place users name in *_user - * return 1 if listed 0 if not. - */ - -static int lookup(const char *name, char *list, const char **_user) -{ - int anon = 0; - - *_user = name; /* this is the default */ - if (list) { - const char *l; - char *x; - - x = list; - while ((l = strtok(x, ","))) { - x = NULL; - if (!strcmp(name, l)) { - *_user = list; - anon = 1; - } - } - } else { -#define MAX_L 2 - static const char *l[MAX_L] = { "ftp", "anonymous" }; - int i; - - for (i=0; i<MAX_L; ++i) { - if (!strcmp(l[i], name)) { - *_user = l[0]; - anon = 1; - break; - } - } - } - - return anon; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int retval, anon=0, ctrl; - const char *user; - char *users=NULL; - - /* - * this module checks if the user name is ftp or annonymous. If - * this is the case, it can set the PAM_RUSER to the entered email - * address and SUCCEEDS, otherwise it FAILS. - */ - - ctrl = _pam_parse(argc, argv, &users); - - retval = pam_get_user(pamh, &user, NULL); - if (retval != PAM_SUCCESS || user == NULL) { - _pam_log(LOG_ERR, "no user specified"); - return PAM_USER_UNKNOWN; - } - - if (!(ctrl & PAM_NO_ANON)) { - anon = lookup(user, users, &user); - } - - if (anon) { - retval = pam_set_item(pamh, PAM_USER, (const void *)user); - if (retval != PAM_SUCCESS || user == NULL) { - _pam_log(LOG_ERR, "user resetting failed"); - return PAM_USER_UNKNOWN; - } - } - - /* - * OK. we require an email address for user or the user's password. - * - build conversation and get their input. - */ - - { - struct pam_message msg[1], *mesg[1]; - struct pam_response *resp=NULL; - const char *token; - char *prompt=NULL; - int i=0; - - if (!anon) { - prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user)); - if (prompt == NULL) { - D(("out of memory!?")); - return PAM_BUF_ERR; - } else { - sprintf(prompt, PLEASE_ENTER_PASSWORD, user); - msg[i].msg = prompt; - } - } else { - msg[i].msg = GUEST_LOGIN_PROMPT; - } - - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - mesg[i] = &msg[i]; - - retval = converse(pamh, ++i, mesg, &resp); - if (prompt) { - _pam_overwrite(prompt); - _pam_drop(prompt); - } - - if (retval != PAM_SUCCESS) { - if (resp != NULL) - _pam_drop_reply(resp,i); - return ((retval == PAM_CONV_AGAIN) - ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL); - } - - if (anon) { - /* XXX: Some effort should be made to verify this email address! */ - - if (!(ctrl & PAM_IGNORE_EMAIL)) { - token = strtok(resp->resp, "@"); - retval = pam_set_item(pamh, PAM_RUSER, token); - - if ((token) && (retval == PAM_SUCCESS)) { - token = strtok(NULL, "@"); - retval = pam_set_item(pamh, PAM_RHOST, token); - } - } - - /* we are happy to grant annonymous access to the user */ - retval = PAM_SUCCESS; - - } else { - /* - * we have a password so set AUTHTOK - */ - - (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp); - - /* - * this module failed, but the next one might succeed with - * this password. - */ - - retval = PAM_AUTH_ERR; - } - - if (resp) { /* clean up */ - _pam_drop_reply(resp, i); - } - - /* success or failure */ - - return retval; - } -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_IGNORE; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_ftp_modstruct = { - "pam_ftp", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_group/.cvsignore b/modules/pam_group/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_group/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_group/Makefile b/modules/pam_group/Makefile deleted file mode 100644 index cb3c4c89..00000000 --- a/modules/pam_group/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# - -include ../../Make.Rules - -TITLE=pam_group -LOCAL_CONFILE=./group.conf -INSTALLED_CONFILE=$(SCONFIGD)/group.conf - -DEFS=-DDEFAULT_CONF_FILE=\"$(CONFILE)\" -CFLAGS += $(DEFS) - -MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" -MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) -MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age - -include ../Simple.Rules diff --git a/modules/pam_group/group.conf b/modules/pam_group/group.conf deleted file mode 100644 index e721b990..00000000 --- a/modules/pam_group/group.conf +++ /dev/null @@ -1,60 +0,0 @@ -## -## Note, to get this to work as it is currently typed you need -## -## 1. to run an application as root -## 2. add the following groups to the /etc/group file: -## floppy, games, sound -## -# -# *** Please note that giving group membership on a session basis is -# *** NOT inherently secure. If a user can create an executable that -# *** is setgid a group that they are infrequently given membership -# *** of, they can basically obtain group membership any time they -# *** like. Example: games are allowed between the hours of 6pm and 6am -# *** user joe logs in at 7pm writes a small C-program toplay.c that -# *** invokes their favorite shell, compiles it and does -# *** "chgrp games toplay; chmod g+s toplay". They are basically able -# *** to play games any time... You have been warned. AGM -# -# this is an example configuration file for the pam_group module. Its -# syntax is based on that of the pam_time module and (at some point in -# the distant past was inspired by the 'shadow' package) -# -# the syntax of the lines is as follows: -# -# services;ttys;users;times;groups -# -# white space is ignored and lines maybe extended with '\\n' (escaped -# newlines). From reading these comments, it is clear that -# text following a '#' is ignored to the end of the line. -# -# the first four fields are described in the pam_time directory. -# The only difference for these is how the time field is interpretted: -# it is used to indicate "when" these groups are to be given to the user. -# -# groups -# The (comma or space separated) list of groups that the user -# inherits membership of. These groups are added if the previous -# fields are satisfied by the user's request -# - -# -# Here is a simple example: running 'xsh' on tty* (any ttyXXX device), -# the user 'us' is given access to the floppy (through membership of -# the floppy group) -# - -#xsh;tty*&!ttyp*;us;Al0000-2400;floppy - -# -# another example: running 'xsh' on tty* (any ttyXXX device), -# the user 'sword' is given access to games (through membership of -# the floppy group) after work hours -# - -#xsh; tty* ;sword;!Wk0900-1800;games, sound -#xsh; tty* ;*;Al0900-1800;floppy - -# -# End of group.conf file -# diff --git a/modules/pam_group/pam_group.c b/modules/pam_group/pam_group.c deleted file mode 100644 index 4f6f34fb..00000000 --- a/modules/pam_group/pam_group.c +++ /dev/null @@ -1,856 +0,0 @@ -/* pam_group module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/7/6 - */ - -const static char rcsid[] = -"$Id$;\n" -"Version 0.5 for Linux-PAM\n" -"Copyright (c) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; - -#define _BSD_SOURCE - -#include <sys/file.h> -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <unistd.h> -#include <stdarg.h> -#include <time.h> -#include <syslog.h> -#include <string.h> - -#include <grp.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef DEFAULT_CONF_FILE -# define PAM_GROUP_CONF DEFAULT_CONF_FILE /* from external define */ -#else -# define PAM_GROUP_CONF "/etc/security/group.conf" -#endif -#define PAM_GROUP_BUFLEN 1000 -#define FIELD_SEPARATOR ';' /* this is new as of .02 */ - -#ifdef TRUE -# undef TRUE -#endif -#ifdef FALSE -# undef FALSE -#endif - -typedef enum { FALSE, TRUE } boolean; -typedef enum { AND, OR } operator; - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* --- static functions for checking whether the user should be let in --- */ - -static void _log_err(const char *format, ... ) -{ - va_list args; - - va_start(args, format); - openlog("pam_group", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(LOG_CRIT, format, args); - va_end(args); - closelog(); -} - -static void shift_bytes(char *mem, int from, int by) -{ - while (by-- > 0) { - *mem = mem[from]; - ++mem; - } -} - -static int read_field(int fd, char **buf, int *from, int *to) -{ - /* is buf set ? */ - - if (! *buf) { - *buf = (char *) malloc(PAM_GROUP_BUFLEN); - if (! *buf) { - _log_err("out of memory"); - return -1; - } - *from = *to = 0; - fd = open(PAM_GROUP_CONF, O_RDONLY); - } - - /* do we have a file open ? return error */ - - if (fd < 0 && *to <= 0) { - _log_err( PAM_GROUP_CONF " not opened"); - memset(*buf, 0, PAM_GROUP_BUFLEN); - _pam_drop(*buf); - return -1; - } - - /* check if there was a newline last time */ - - if ((*to > *from) && (*to > 0) - && ((*buf)[*from] == '\0')) { /* previous line ended */ - (*from)++; - (*buf)[0] = '\0'; - return fd; - } - - /* ready for more data: first shift the buffer's remaining data */ - - *to -= *from; - shift_bytes(*buf, *from, *to); - *from = 0; - (*buf)[*to] = '\0'; - - while (fd >= 0 && *to < PAM_GROUP_BUFLEN) { - int i; - - /* now try to fill the remainder of the buffer */ - - i = read(fd, *to + *buf, PAM_GROUP_BUFLEN - *to); - if (i < 0) { - _log_err("error reading " PAM_GROUP_CONF); - return -1; - } else if (!i) { - close(fd); - fd = -1; /* end of file reached */ - } else - *to += i; - - /* - * contract the buffer. Delete any comments, and replace all - * multiple spaces with single commas - */ - - i = 0; -#ifdef DEBUG_DUMP - D(("buffer=<%s>",*buf)); -#endif - while (i < *to) { - if ((*buf)[i] == ',') { - int j; - - for (j=++i; j<*to && (*buf)[j] == ','; ++j); - if (j!=i) { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - } - } - switch ((*buf)[i]) { - int j,c; - case '#': - for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); - if (j >= *to) { - (*buf)[*to = ++i] = '\0'; - } else if (c == '\n') { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - ++i; - } else { - _log_err("internal error in " __FILE__ - " at line %d", __LINE__ ); - return -1; - } - break; - case '\\': - if ((*buf)[i+1] == '\n') { - shift_bytes(i + *buf, 2, *to - (i+2)); - *to -= 2; - } else { - ++i; /* we don't escape non-newline characters */ - } - break; - case '!': - case ' ': - case '\t': - if ((*buf)[i] != '!') - (*buf)[i] = ','; - /* delete any trailing spaces */ - for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' - || c == '\t' ); ++j); - shift_bytes(i + *buf, j-i, (*to)-j ); - *to -= j-i; - break; - default: - ++i; - } - } - } - - (*buf)[*to] = '\0'; - - /* now return the next field (set the from/to markers) */ - { - int i; - - for (i=0; i<*to; ++i) { - switch ((*buf)[i]) { - case '#': - case '\n': /* end of the line/file */ - (*buf)[i] = '\0'; - *from = i; - return fd; - case FIELD_SEPARATOR: /* end of the field */ - (*buf)[i] = '\0'; - *from = ++i; - return fd; - } - } - *from = i; - (*buf)[*from] = '\0'; - } - - if (*to <= 0) { - D(("[end of text]")); - *buf = NULL; - } - return fd; -} - -/* read a member from a field */ - -static int logic_member(const char *string, int *at) -{ - int len,c,to; - int done=0; - int token=0; - - len=0; - to=*at; - do { - c = string[to++]; - - switch (c) { - - case '\0': - --to; - done = 1; - break; - - case '&': - case '|': - case '!': - if (token) { - --to; - } - done = 1; - break; - - default: - if (isalpha(c) || c == '*' || isdigit(c) || c == '_' - || c == '-' || c == '.' || c == '/') { - token = 1; - } else if (token) { - --to; - done = 1; - } else { - ++*at; - } - } - } while (!done); - - return to - *at; -} - -typedef enum { VAL, OP } expect; - -static boolean logic_field(const void *me, const char *x, int rule, - boolean (*agrees)(const void *, const char * - , int, int)) -{ - boolean left=FALSE, right, not=FALSE; - operator oper=OR; - int at=0, l; - expect next=VAL; - - while ((l = logic_member(x,&at))) { - int c = x[at]; - - if (next == VAL) { - if (c == '!') - not = !not; - else if (isalpha(c) || c == '*') { - right = not ^ agrees(me, x+at, l, rule); - if (oper == AND) - left &= right; - else - left |= right; - next = OP; - } else { - _log_err("garbled syntax; expected name (rule #%d)", rule); - return FALSE; - } - } else { /* OP */ - switch (c) { - case '&': - oper = AND; - break; - case '|': - oper = OR; - break; - default: - _log_err("garbled syntax; expected & or | (rule #%d)" - , rule); - D(("%c at %d",c,at)); - return FALSE; - } - next = VAL; - } - at += l; - } - - return left; -} - -static boolean is_same(const void *A, const char *b, int len, int rule) -{ - int i; - const char *a; - - a = A; - for (i=0; len > 0; ++i, --len) { - if (b[i] != a[i]) { - if (b[i++] == '*') { - return (!--len || !strncmp(b+i,a+strlen(a)-len,len)); - } else - return FALSE; - } - } - return ( !len ); -} - -typedef struct { - int day; /* array of 7 bits, one set for today */ - int minute; /* integer, hour*100+minute for now */ -} TIME; - -struct day { - const char *d; - int bit; -} static const days[11] = { - { "su", 01 }, - { "mo", 02 }, - { "tu", 04 }, - { "we", 010 }, - { "th", 020 }, - { "fr", 040 }, - { "sa", 0100 }, - { "wk", 076 }, - { "wd", 0101 }, - { "al", 0177 }, - { NULL, 0 } -}; - -static TIME time_now(void) -{ - struct tm *local; - time_t the_time; - TIME this; - - the_time = time((time_t *)0); /* get the current time */ - local = localtime(&the_time); - this.day = days[local->tm_wday].bit; - this.minute = local->tm_hour*100 + local->tm_min; - - D(("day: 0%o, time: %.4d", this.day, this.minute)); - return this; -} - -/* take the current date and see if the range "date" passes it */ -static boolean check_time(const void *AT, const char *times, int len, int rule) -{ - boolean not,pass; - int marked_day, time_start, time_end; - const TIME *at; - int i,j=0; - - at = AT; - D(("checking: 0%o/%.4d vs. %s", at->day, at->minute, times)); - - if (times == NULL) { - /* this should not happen */ - _log_err("internal error: " __FILE__ " line %d", __LINE__); - return FALSE; - } - - if (times[j] == '!') { - ++j; - not = TRUE; - } else { - not = FALSE; - } - - for (marked_day = 0; len > 0 && isalpha(times[j]); --len) { - int this_day=-1; - - D(("%c%c ?", times[j], times[j+1])); - for (i=0; days[i].d != NULL; ++i) { - if (tolower(times[j]) == days[i].d[0] - && tolower(times[j+1]) == days[i].d[1] ) { - this_day = days[i].bit; - break; - } - } - j += 2; - if (this_day == -1) { - _log_err("bad day specified (rule #%d)", rule); - return FALSE; - } - marked_day ^= this_day; - } - if (marked_day == 0) { - _log_err("no day specified"); - return FALSE; - } - D(("day range = 0%o", marked_day)); - - time_start = 0; - for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) { - time_start *= 10; - time_start += times[i+j]-'0'; /* is this portable? */ - } - j += i; - - if (times[j] == '-') { - time_end = 0; - for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) { - time_end *= 10; - time_end += times[i+j]-'0'; /* is this portable? */ - } - j += i; - } else - time_end = -1; - - D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j])); - if (i != 5 || time_end == -1) { - _log_err("no/bad times specified (rule #%d)", rule); - return TRUE; - } - D(("times(%d to %d)", time_start,time_end)); - D(("marked_day = 0%o", marked_day)); - - /* compare with the actual time now */ - - pass = FALSE; - if (time_start < time_end) { /* start < end ? --> same day */ - if ((at->day & marked_day) && (at->minute >= time_start) - && (at->minute < time_end)) { - D(("time is listed")); - pass = TRUE; - } - } else { /* spans two days */ - if ((at->day & marked_day) && (at->minute >= time_start)) { - D(("caught on first day")); - pass = TRUE; - } else { - marked_day <<= 1; - marked_day |= (marked_day & 0200) ? 1:0; - D(("next day = 0%o", marked_day)); - if ((at->day & marked_day) && (at->minute <= time_end)) { - D(("caught on second day")); - pass = TRUE; - } - } - } - - return (not ^ pass); -} - -static int find_member(const char *string, int *at) -{ - int len,c,to; - int done=0; - int token=0; - - len=0; - to=*at; - do { - c = string[to++]; - - switch (c) { - - case '\0': - --to; - done = 1; - break; - - case '&': - case '|': - case '!': - if (token) { - --to; - } - done = 1; - break; - - default: - if (isalpha(c) || isdigit(c) || c == '_' || c == '*' - || c == '-') { - token = 1; - } else if (token) { - --to; - done = 1; - } else { - ++*at; - } - } - } while (!done); - - return to - *at; -} - -#define GROUP_BLK 10 -#define blk_size(len) (((len-1 + GROUP_BLK)/GROUP_BLK)*GROUP_BLK) - -static int mkgrplist(char *buf, gid_t **list, int len) -{ - int l,at=0; - int blks; - - blks = blk_size(len); - D(("cf. blks=%d and len=%d", blks,len)); - - while ((l = find_member(buf,&at))) { - int edge; - - if (len >= blks) { - gid_t *tmp; - - D(("allocating new block")); - tmp = (gid_t *) realloc((*list) - , sizeof(gid_t) * (blks += GROUP_BLK)); - if (tmp != NULL) { - (*list) = tmp; - } else { - _log_err("out of memory for group list"); - free(*list); - (*list) = NULL; - return -1; - } - } - - /* '\0' terminate the entry */ - - edge = (buf[at+l]) ? 1:0; - buf[at+l] = '\0'; - D(("found group: %s",buf+at)); - - /* this is where we convert a group name to a gid_t */ -#ifdef WANT_PWDB - { - int retval; - const struct pwdb *pw=NULL; - - retval = pwdb_locate("group", PWDB_DEFAULT, buf+at - , PWDB_ID_UNKNOWN, &pw); - if (retval != PWDB_SUCCESS) { - _log_err("bad group: %s; %s", buf+at, pwdb_strerror(retval)); - } else { - const struct pwdb_entry *pwe=NULL; - - D(("group %s exists", buf+at)); - retval = pwdb_get_entry(pw, "gid", &pwe); - if (retval == PWDB_SUCCESS) { - D(("gid = %d [%p]",* (const gid_t *) pwe->value,list)); - (*list)[len++] = * (const gid_t *) pwe->value; - pwdb_entry_delete(&pwe); /* tidy up */ - } else { - _log_err("%s group entry is bad; %s" - , pwdb_strerror(retval)); - } - pw = NULL; /* break link - cached for later use */ - } - } -#else - { - const struct group *grp; - - grp = getgrnam(buf+at); - if (grp == NULL) { - _log_err("bad group: %s", buf+at); - } else { - D(("group %s exists", buf+at)); - (*list)[len++] = grp->gr_gid; - } - } -#endif - - /* next entry along */ - - at += l + edge; - } - D(("returning with [%p/len=%d]->%p",list,len,*list)); - return len; -} - - -static int check_account(const char *service, const char *tty - , const char *user) -{ - int from=0,to=0,fd=-1; - char *buffer=NULL; - int count=0; - TIME here_and_now; - int retval=PAM_SUCCESS; - gid_t *grps; - int no_grps; - - /* - * first we get the current list of groups - the application - * will have previously done an initgroups(), or equivalent. - */ - - D(("counting supplementary groups")); - no_grps = getgroups(0, NULL); /* find the current number of groups */ - if (no_grps > 0) { - grps = calloc( blk_size(no_grps) , sizeof(gid_t) ); - D(("copying current list into grps [%d big]",blk_size(no_grps))); - (void) getgroups(no_grps, grps); -#ifdef DEBUG - { - int z; - for (z=0; z<no_grps; ++z) { - D(("gid[%d]=%d", z, grps[z])); - } - } -#endif - } else { - D(("no supplementary groups known")); - no_grps = 0; - grps = NULL; - } - - here_and_now = time_now(); /* find current time */ - - /* parse the rules in the configuration file */ - do { - int good=TRUE; - - /* here we get the service name field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - /* empty line .. ? */ - continue; - } - ++count; - D(("working on rule #%d",count)); - - good = logic_field(service, buffer, count, is_same); - D(("with service: %s", good ? "passes":"fails" )); - - /* here we get the terminal name field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_GROUP_CONF "; no tty entry #%d", count); - continue; - } - good &= logic_field(tty, buffer, count, is_same); - D(("with tty: %s", good ? "passes":"fails" )); - - /* here we get the username field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_GROUP_CONF "; no user entry #%d", count); - continue; - } - good &= logic_field(user, buffer, count, is_same); - D(("with user: %s", good ? "passes":"fails" )); - - /* here we get the time field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_GROUP_CONF "; no time entry #%d", count); - continue; - } - - good &= logic_field(&here_and_now, buffer, count, check_time); - D(("with time: %s", good ? "passes":"fails" )); - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_GROUP_CONF "; no listed groups for rule #%d" - , count); - continue; - } - - /* - * so we have a list of groups, we need to turn it into - * something to send to setgroups(2) - */ - - if (good) { - D(("adding %s to gid list", buffer)); - good = mkgrplist(buffer, &grps, no_grps); - if (good < 0) { - no_grps = 0; - } else { - no_grps = good; - } - } - - /* check the line is terminated correctly */ - - fd = read_field(fd,&buffer,&from,&to); - if (buffer && buffer[0]) { - _log_err(PAM_GROUP_CONF "; poorly terminated rule #%d", count); - } - - if (good > 0) { - D(("rule #%d passed, added %d groups", count, good)); - } else if (good < 0) { - retval = PAM_BUF_ERR; - } else { - D(("rule #%d failed", count)); - } - - } while (buffer); - - /* now set the groups for the user */ - - if (no_grps > 0) { - int err; - D(("trying to set %d groups", no_grps)); -#ifdef DEBUG - for (err=0; err<no_grps; ++err) { - D(("gid[%d]=%d", err, grps[err])); - } -#endif - if ((err = setgroups(no_grps, grps))) { - D(("but couldn't set groups %d", err)); - _log_err("unable to set the group membership for user (err=%d)" - , err); - retval = PAM_CRED_ERR; - } - } - - if (grps) { /* tidy up */ - memset(grps, 0, sizeof(gid_t) * blk_size(no_grps)); - _pam_drop(grps); - no_grps = 0; - } - - return retval; -} - -/* --- public authentication management functions --- */ - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - return PAM_IGNORE; -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - const char *service=NULL, *tty=NULL; - const char *user=NULL; - int retval; - unsigned setting; - - /* only interested in establishing credentials */ - - setting = flags; - if (!(setting & PAM_ESTABLISH_CRED)) { - D(("ignoring call - not for establishing credentials")); - return PAM_SUCCESS; /* don't fail because of this */ - } - - /* set service name */ - - if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) - != PAM_SUCCESS || service == NULL) { - _log_err("cannot find the current service name"); - return PAM_ABORT; - } - - /* set username */ - - if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL - || *user == '\0') { - _log_err("cannot determine the user's name"); - return PAM_USER_UNKNOWN; - } - - /* set tty name */ - - if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS - || tty == NULL) { - D(("PAM_TTY not set, probing stdin")); - tty = ttyname(STDIN_FILENO); - if (tty == NULL) { - _log_err("couldn't get the tty name"); - return PAM_ABORT; - } - if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { - _log_err("couldn't set tty name"); - return PAM_ABORT; - } - } - - if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */ - tty += 5; - } - - /* good, now we have the service name, the user and the terminal name */ - - D(("service=%s", service)); - D(("user=%s", user)); - D(("tty=%s", tty)); - -#ifdef WANT_PWDB - - /* We initialize the pwdb library and check the account */ - retval = pwdb_start(); /* initialize */ - if (retval == PWDB_SUCCESS) { - retval = check_account(service,tty,user); /* get groups */ - (void) pwdb_end(); /* tidy up */ - } else { - D(("failed to initialize pwdb; %s", pwdb_strerror(retval))); - _log_err("unable to initialize libpwdb"); - retval = PAM_ABORT; - } - -#else /* WANT_PWDB */ - retval = check_account(service,tty,user); /* get groups */ -#endif /* WANT_PWDB */ - - return retval; -} - -/* end of module definition */ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_group_modstruct = { - "pam_group", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL -}; -#endif diff --git a/modules/pam_issue/.cvsignore b/modules/pam_issue/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_issue/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_issue/Makefile b/modules/pam_issue/Makefile deleted file mode 100644 index d73710e1..00000000 --- a/modules/pam_issue/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_issue - -include ../Simple.Rules diff --git a/modules/pam_issue/pam_issue.c b/modules/pam_issue/pam_issue.c deleted file mode 100644 index 1f4853de..00000000 --- a/modules/pam_issue/pam_issue.c +++ /dev/null @@ -1,308 +0,0 @@ -/* pam_issue module - a simple /etc/issue parser to set PAM_USER_PROMPT - * - * Copyright 1999 by Ben Collins <bcollins@debian.org> - * - * Needs to be called before any other auth modules so we can setup the - * user prompt before it's first used. Allows one argument option, which - * is the full path to a file to be used for issue (uses /etc/issue as a - * default) such as "issue=/etc/issue.telnet". - * - * We can also parse escapes within the the issue file (enabled by - * default, but can be disabled with the "noesc" option). It's the exact - * same parsing as util-linux's agetty program performs. - * - * Released under the GNU LGPL version 2 or later - */ - -#define _GNU_SOURCE -#define _BSD_SOURCE - -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <sys/utsname.h> -#include <utmp.h> -#include <malloc.h> -#include <time.h> - -#include <security/_pam_macros.h> - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -static int _user_prompt_set = 0; - -char *do_prompt (FILE *); - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - int retval = PAM_SUCCESS; - FILE *fd; - int parse_esc = 1; - char *prompt_tmp = NULL; - const char *cur_prompt = NULL; - struct stat st; - char *issue_file = NULL; - - /* If we've already set the prompt, don't set it again */ - if(_user_prompt_set) - return PAM_IGNORE; - else - /* we set this here so if we fail below, we wont get further - than this next time around (only one real failure) */ - _user_prompt_set = 1; - - for ( ; argc-- > 0 ; ++argv ) { - if (!strncmp(*argv,"issue=",6)) { - issue_file = (char *) strdup(6+*argv); - if (issue_file != NULL) { - D(("set issue_file to: %s", issue_file)); - } else { - D(("failed to strdup issue_file - ignored")); - return PAM_IGNORE; - } - } else if (!strcmp(*argv,"noesc")) { - parse_esc = 0; - D(("turning off escape parsing by request")); - } else - D(("unknown option passed: %s", *argv)); - } - - if (issue_file == NULL) - issue_file = strdup("/etc/issue"); - - if ((fd = fopen(issue_file, "r")) != NULL) { - int tot_size = 0; - - if (fstat(fileno(fd), &st) < 0) - return PAM_IGNORE; - - retval = pam_get_item(pamh, PAM_USER_PROMPT, - (const void **) &cur_prompt); - if (retval != PAM_SUCCESS) { - return PAM_IGNORE; - } - if (cur_prompt == NULL) { - cur_prompt = ""; - } - - /* first read in the issue file */ - - if (parse_esc) { - prompt_tmp = do_prompt(fd); - if (prompt_tmp == NULL) { - return PAM_IGNORE; - } - } else { - int count = 0; - - prompt_tmp = malloc(st.st_size + 1); - if (prompt_tmp == NULL) { - return PAM_IGNORE; - } - memset (prompt_tmp, '\0', st.st_size + 1); - count = fread(prompt_tmp, sizeof(char *), st.st_size, fd); - if (count != st.st_size) { - free(prompt_tmp); - return PAM_IGNORE; - } - prompt_tmp[st.st_size] = '\0'; - } - - fclose(fd); - - tot_size = strlen(prompt_tmp) + strlen(cur_prompt) + 1; - - /* - * alloc some extra space for the original prompt - * and postpend it to the buffer - */ - { - char *prompt_tmp_tmp = prompt_tmp; - - prompt_tmp = realloc(prompt_tmp, tot_size); - if (prompt_tmp == NULL) { - prompt_tmp = prompt_tmp_tmp; - retval = PAM_IGNORE; - goto cleanup; - } - } - - strcpy(prompt_tmp+strlen(prompt_tmp), cur_prompt); - - prompt_tmp[tot_size] = '\0'; - - retval = pam_set_item(pamh, PAM_USER_PROMPT, - (const char *) prompt_tmp); - - cleanup: - free(issue_file); - free(prompt_tmp); - - } else { - D(("could not open issue_file: %s", issue_file)); - return PAM_IGNORE; - } - - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return PAM_IGNORE; -} - -char *do_prompt(FILE *fd) -{ - int c, size = 1024; - char *issue = (char *)malloc(size); - char buf[1024]; - struct utsname uts; - - if (issue == NULL || fd == NULL) - return NULL; - - issue[0] = '\0'; /* zero this, for strcat to work on first buf */ - (void) uname(&uts); - - while ((c = getc(fd)) != EOF) { - if (c == '\\') { - c = getc(fd); - switch (c) { - case 's': - snprintf (buf, 1024, "%s", uts.sysname); - break; - case 'n': - snprintf (buf, 1024, "%s", uts.nodename); - break; - case 'r': - snprintf (buf, 1024, "%s", uts.release); - break; - case 'v': - snprintf (buf, 1024, "%s", uts.version); - break; - case 'm': - snprintf (buf, 1024, "%s", uts.machine); - break; - case 'o': - { - char domainname[256]; - - getdomainname(domainname, sizeof(domainname)); - domainname[sizeof(domainname)-1] = '\0'; - snprintf (buf, 1024, "%s", domainname); - } - break; - - case 'd': - case 't': - { - const char *weekday[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", - "Fri", "Sat" }; - const char *month[] = { - "Jan", "Feb", "Mar", "Apr", "May", - "Jun", "Jul", "Aug", "Sep", "Oct", - "Nov", "Dec" }; - time_t now; - struct tm *tm; - - (void) time (&now); - tm = localtime(&now); - - if (c == 'd') - snprintf (buf, 1024, "%s %s %d %d", - weekday[tm->tm_wday], month[tm->tm_mon], - tm->tm_mday, - tm->tm_year + 1900); - else - snprintf (buf, 1024, "%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - break; - case 'l': - { - char *ttyn = ttyname(1); - if (!strncmp(ttyn, "/dev/", 5)) - ttyn += 5; - snprintf (buf, 1024, "%s", ttyn); - } - break; - case 'u': - case 'U': - { - int users = 0; - struct utmp *ut; - setutent(); - while ((ut = getutent())) - if (ut->ut_type == USER_PROCESS) - users++; - endutent(); - printf ("%d ", users); - if (c == 'U') - snprintf (buf, 1024, "%s", (users == 1) ? - " user" : " users"); - break; - } - default: - buf[0] = c; buf[1] = '\0'; - } - if ((strlen(issue) + strlen(buf)) < size + 1) { - char *old_issue = issue; - - size += strlen(buf) + 1; - issue = (char *) realloc (issue, size); - if (issue == NULL) { - free(old_issue); - return NULL; - } - } - strcat(issue, buf); - } else { - buf[0] = c; buf[1] = '\0'; - if ((strlen(issue) + strlen(buf)) < size + 1) { - char *old_issue = issue; - - size += strlen(buf) + 1; - issue = (char *) realloc (issue, size); - if (issue == NULL) { - free(old_issue); - return NULL; - } - } - strcat(issue, buf); - } - } - - return issue; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_issue_modstruct = { - "pam_issue", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_lastlog/.cvsignore b/modules/pam_lastlog/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_lastlog/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_lastlog/Makefile b/modules/pam_lastlog/Makefile deleted file mode 100644 index 333ecd93..00000000 --- a/modules/pam_lastlog/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -ifeq ($(HAVE_LIBUTIL),yes) - MODULE_SIMPLE_EXTRALIBS += -lutil -endif - -TITLE=pam_lastlog - -include ../Simple.Rules diff --git a/modules/pam_lastlog/pam_lastlog.c b/modules/pam_lastlog/pam_lastlog.c deleted file mode 100644 index c86becd8..00000000 --- a/modules/pam_lastlog/pam_lastlog.c +++ /dev/null @@ -1,462 +0,0 @@ -/* pam_lastlog module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 - * - * This module does the necessary work to display the last login - * time+date for this user, it then updates this entry for the - * present (login) service. - */ - -#include <security/_pam_aconf.h> - -#include <fcntl.h> -#include <time.h> -#ifdef HAVE_UTMP_H -# include <utmp.h> -#else -# include <lastlog.h> -#endif -#include <pwd.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> -#include <unistd.h> - -#ifdef WANT_PWDB -#include <pwdb/pwdb_public.h> /* use POSIX front end */ -#endif - -#if defined(hpux) || defined(sunos) || defined(solaris) -# ifndef _PATH_LASTLOG -# define _PATH_LASTLOG "/usr/adm/lastlog" -# endif /* _PATH_LASTLOG */ -# ifndef UT_HOSTSIZE -# define UT_HOSTSIZE 16 -# endif /* UT_HOSTSIZE */ -# ifndef UT_LINESIZE -# define UT_LINESIZE 12 -# endif /* UT_LINESIZE */ -#endif -#if defined(hpux) -struct lastlog { - time_t ll_time; - char ll_line[UT_LINESIZE]; - char ll_host[UT_HOSTSIZE]; /* same as in utmp */ -}; -#endif /* hpux */ - -/* XXX - time before ignoring lock. Is 1 sec enough? */ -#define LASTLOG_IGNORE_LOCK_TIME 1 - -#define DEFAULT_HOST "" /* "[no.where]" */ -#define DEFAULT_TERM "" /* "tt???" */ -#define LASTLOG_NEVER_WELCOME "Welcome to your new account!" -#define LASTLOG_INTRO "Last login:" -#define LASTLOG_TIME " %s" -#define _LASTLOG_HOST_FORMAT " from %%.%ds" -#define _LASTLOG_LINE_FORMAT " on %%.%ds" -#define LASTLOG_TAIL "" -#define LASTLOG_MAXSIZE (sizeof(LASTLOG_INTRO)+0 \ - +sizeof(LASTLOG_TIME)+strlen(the_time) \ - +sizeof(_LASTLOG_HOST_FORMAT)+UT_HOSTSIZE \ - +sizeof(_LASTLOG_LINE_FORMAT)+UT_LINESIZE \ - +sizeof(LASTLOG_TAIL)) - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_SESSION - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* some syslogging */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-lastlog", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define LASTLOG_DATE 01 /* display the date of the last login */ -#define LASTLOG_HOST 02 /* display the last host used (if set) */ -#define LASTLOG_LINE 04 /* display the last terminal used */ -#define LASTLOG_NEVER 010 /* display a welcome message for first login */ -#define LASTLOG_DEBUG 020 /* send info to syslog(3) */ -#define LASTLOG_QUIET 040 /* keep quiet about things */ - -static int _pam_parse(int flags, int argc, const char **argv) -{ - int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE); - - /* does the appliction require quiet? */ - if (flags & PAM_SILENT) { - ctrl |= LASTLOG_QUIET; - } - - /* step through arguments */ - for (; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) { - ctrl |= LASTLOG_DEBUG; - } else if (!strcmp(*argv,"nodate")) { - ctrl |= ~LASTLOG_DATE; - } else if (!strcmp(*argv,"noterm")) { - ctrl |= ~LASTLOG_LINE; - } else if (!strcmp(*argv,"nohost")) { - ctrl |= ~LASTLOG_HOST; - } else if (!strcmp(*argv,"silent")) { - ctrl |= LASTLOG_QUIET; - } else if (!strcmp(*argv,"never")) { - ctrl |= LASTLOG_NEVER; - } else { - _log_err(LOG_ERR,"unknown option; %s",*argv); - } - } - - D(("ctrl = %o", ctrl)); - return ctrl; -} - -/* a front end for conversations */ - -static int converse(pam_handle_t *pamh, int ctrl, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { - - retval = conv->conv(nargs, ( const struct pam_message ** ) message - , response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && (ctrl & LASTLOG_DEBUG) ) { - _log_err(LOG_DEBUG, "conversation failure [%s]" - , pam_strerror(pamh, retval)); - } - - } else { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - , pam_strerror(pamh, retval)); - } - - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -static int make_remark(pam_handle_t *pamh, int ctrl, const char *remark) -{ - int retval; - - if (!(ctrl & LASTLOG_QUIET)) { - struct pam_message msg[1], *mesg[1]; - struct pam_response *resp=NULL; - - mesg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = remark; - - retval = converse(pamh, ctrl, 1, mesg, &resp); - - msg[0].msg = NULL; - if (resp) { - _pam_drop_reply(resp, 1); - } - } else { - D(("keeping quiet")); - retval = PAM_SUCCESS; - } - - D(("returning %s", pam_strerror(pamh, retval))); - return retval; -} - -/* - * Values for the announce flags.. - */ - -static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) -{ - struct flock last_lock; - struct lastlog last_login; - int retval = PAM_SESSION_ERR; - int last_fd; - - /* obtain the last login date and all the relevant info */ - last_fd = open(_PATH_LASTLOG, O_RDWR); - if (last_fd < 0) { - D(("unable to open the %s file", _PATH_LASTLOG)); - if (announce & LASTLOG_DEBUG) { - _log_err(LOG_DEBUG, "unable to open %s file", _PATH_LASTLOG); - } - retval = PAM_PERM_DENIED; - } else { - int win; - - /* read the lastlogin file - for this uid */ - (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET); - - memset(&last_lock, 0, sizeof(last_lock)); - last_lock.l_type = F_RDLCK; - last_lock.l_whence = SEEK_SET; - last_lock.l_start = sizeof(last_login) * (off_t) uid; - last_lock.l_len = sizeof(last_login); - - if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) { - D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); - _log_err(LOG_ALERT, "%s file is locked/read", _PATH_LASTLOG); - sleep(LASTLOG_IGNORE_LOCK_TIME); - } - - win = ( read(last_fd, &last_login, sizeof(last_login)) - == sizeof(last_login) ); - - last_lock.l_type = F_UNLCK; - (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ - - if (!win) { - D(("First login for user uid=%d", _PATH_LASTLOG, uid)); - if (announce & LASTLOG_DEBUG) { - _log_err(LOG_DEBUG, "creating lastlog for uid %d", uid); - } - memset(&last_login, 0, sizeof(last_login)); - } - - /* rewind */ - (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET); - - if (!(announce & LASTLOG_QUIET)) { - if (last_login.ll_time) { - char *the_time; - char *remark; - - the_time = ctime(&last_login.ll_time); - the_time[-1+strlen(the_time)] = '\0'; /* delete '\n' */ - - remark = malloc(LASTLOG_MAXSIZE); - if (remark == NULL) { - D(("no memory for last login remark")); - retval = PAM_BUF_ERR; - } else { - int at; - - /* printing prefix */ - at = sprintf(remark, "%s", LASTLOG_INTRO); - - /* we want the date? */ - if (announce & LASTLOG_DATE) { - at += sprintf(remark+at, LASTLOG_TIME, the_time); - } - - /* we want & have the host? */ - if ((announce & LASTLOG_HOST) - && (last_login.ll_host[0] != '\0')) { - char format[2*sizeof(_LASTLOG_HOST_FORMAT)]; - - (void) sprintf(format, _LASTLOG_HOST_FORMAT - , UT_HOSTSIZE); - D(("format: %s", format)); - at += sprintf(remark+at, format, last_login.ll_host); - _pam_overwrite(format); - } - - /* we want and have the terminal? */ - if ((announce & LASTLOG_LINE) - && (last_login.ll_line[0] != '\0')) { - char format[2*sizeof(_LASTLOG_LINE_FORMAT)]; - - (void) sprintf(format, _LASTLOG_LINE_FORMAT - , UT_LINESIZE); - D(("format: %s", format)); - at += sprintf(remark+at, format, last_login.ll_line); - _pam_overwrite(format); - } - - /* display requested combo */ - sprintf(remark+at, "%s", LASTLOG_TAIL); - - retval = make_remark(pamh, announce, remark); - - /* free all the stuff malloced */ - _pam_overwrite(remark); - _pam_drop(remark); - } - } else if ((!last_login.ll_time) && (announce & LASTLOG_NEVER)) { - D(("this is the first time this user has logged in")); - retval = make_remark(pamh, announce, LASTLOG_NEVER_WELCOME); - } - } else { - D(("no text was requested")); - retval = PAM_SUCCESS; - } - - /* write latest value */ - { - const char *remote_host=NULL - , *terminal_line=DEFAULT_TERM; - - /* set this login date */ - D(("set the most recent login time")); - - (void) time(&last_login.ll_time); /* set the time */ - - /* set the remote host */ - (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); - if (remote_host == NULL) { - remote_host = DEFAULT_HOST; - } - - /* copy to last_login */ - strncpy(last_login.ll_host, remote_host, - sizeof(last_login.ll_host)); - last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0'; - remote_host = NULL; - - /* set the terminal line */ - (void) pam_get_item(pamh, PAM_TTY, (const void **)&terminal_line); - D(("terminal = %s", terminal_line)); - if (terminal_line == NULL) { - terminal_line = DEFAULT_TERM; - } else if ( !strncmp("/dev/", terminal_line, 5) ) { - /* strip leading "/dev/" from tty.. */ - terminal_line += 5; - } - D(("terminal = %s", terminal_line)); - - /* copy to last_login */ - strncpy(last_login.ll_line, terminal_line, - sizeof(last_login.ll_line)); - last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0'; - terminal_line = NULL; - - D(("locking last_log file")); - - /* now we try to lock this file-record exclusively; non-blocking */ - memset(&last_lock, 0, sizeof(last_lock)); - last_lock.l_type = F_WRLCK; - last_lock.l_whence = SEEK_SET; - last_lock.l_start = sizeof(last_login) * (off_t) uid; - last_lock.l_len = sizeof(last_login); - - if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) { - D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); - _log_err(LOG_ALERT, "%s file is locked/write", _PATH_LASTLOG); - sleep(LASTLOG_IGNORE_LOCK_TIME); - } - - D(("writing to the last_log file")); - (void) write(last_fd, &last_login, sizeof(last_login)); - - last_lock.l_type = F_UNLCK; - (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ - D(("unlocked")); - - close(last_fd); /* all done */ - } - D(("all done with last login")); - } - - /* reset the last login structure */ - memset(&last_login, 0, sizeof(last_login)); - - return retval; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc - , const char **argv) -{ - int retval, ctrl; - const char *user; - const struct passwd *pwd; - uid_t uid; - - /* - * this module gets the uid of the PAM_USER. Uses it to display - * last login info and then updates the lastlog for that user. - */ - - ctrl = _pam_parse(flags, argc, argv); - - /* which user? */ - - retval = pam_get_item(pamh, PAM_USER, (const void **)&user); - if (retval != PAM_SUCCESS || user == NULL || *user == '\0') { - _log_err(LOG_NOTICE, "user unknown"); - return PAM_USER_UNKNOWN; - } - - /* what uid? */ - - pwd = getpwnam(user); - if (pwd == NULL) { - D(("couldn't identify user %s", user)); - return PAM_CRED_INSUFFICIENT; - } - uid = pwd->pw_uid; - pwd = NULL; /* tidy up */ - - /* process the current login attempt (indicate last) */ - - retval = last_login_date(pamh, ctrl, uid); - - /* indicate success or failure */ - - uid = -1; /* forget this */ - - return retval; -} - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_lastlog_modstruct = { - "pam_lastlog", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_limits/.cvsignore b/modules/pam_limits/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_limits/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_limits/Makefile b/modules/pam_limits/Makefile deleted file mode 100644 index 9473d915..00000000 --- a/modules/pam_limits/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# - -include ../../Make.Rules - -TITLE=pam_limits - -ifeq ($(OS),linux) - -LOCAL_CONFILE=./limits.skel -INSTALLED_CONFILE=$(SCONFIGD)/limits.conf - -DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" -CFLAGS += $(DEFS) - -MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" -MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) -MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age - -include ../Simple.Rules - -else - -include ../dont_makefile - -endif diff --git a/modules/pam_limits/README b/modules/pam_limits/README deleted file mode 100644 index 023b9575..00000000 --- a/modules/pam_limits/README +++ /dev/null @@ -1,107 +0,0 @@ - -pam_limits module: - Imposing user limits on login. - -THEORY OF OPERATION: - -First, make a root-only-readable file (/etc/security/limits.conf by -default or INSTALLED_CONFILE defined Makefile) that describes the -resource limits you wish to impose. No limits are imposed on UID 0 -accounts. - -Each line describes a limit for a user in the form: - -<domain> <type> <item> <value> - -Where: -<domain> can be: - - an user name - - a group name, with @group syntax - - the wildcard *, for default entry - -<type> can have the three values: - - "soft" for enforcing the soft limits - - "hard" for enforcing hard limits - - "-" for enforcing both soft and hard limits - -<item> can be one of the following: - - core - limits the core file size (KB) - - data - max data size (KB) - - fsize - maximum filesize (KB) - - memlock - max locked-in-memory address space (KB) - - nofile - max number of open files - - rss - max resident set size (KB) - - stack - max stack size (KB) - - cpu - max CPU time (MIN) - - nproc - max number of processes - - as - address space limit - - maxlogins - max number of logins for this user - - maxsyslogins - max number of logins on the system - - priority - lower the priority by given value (value can be -ve) - - locks - max locked files (Linux 2.4 and higher) - -Note, if you specify a type of '-' but neglect to supply the item and -value fields then the module will never enforce any limits on the -specified user/group etc. . - -Please remember that individual limits have priority over group -limits, so if you impose no limits for admin group, but one of the -members in this group has a limits line, the user will have its limits -set according to this line. - -Also, please note that all limit settings are set PER LOGIN. They are -not global, nor are they permanent (they apply for the session only). - -In the LIMITS_FILE, the # character introduces a comment - the rest of the -line is ignored. - -The pam_limits module does its best to report configuration problems found -in LIMITS_FILE via syslog. - -EXAMPLE configuration file: -=========================== -* soft core 0 -* hard rss 10000 -@student hard nproc 20 -@faculty soft nproc 20 -@faculty hard nproc 50 -ftp hard nproc 0 -@student - maxlogins 4 - - -ARGUMENTS RECOGNIZED: - debug verbose logging - - conf=/path/to/file the limits configuration file if different from the - one set at compile time. - - change_uid change real uid to the user for who the limits - are set up. Use this option if you have problems - like login not forking a shell for user who has - no processes. Be warned that something else - may break when you do this. - - utmp_early some broken applications actually allocate a - utmp entry for the user before the user is - admitted to the system. If the service you are - configuring PAM for does this, you can use - this module argument to compensate for this - brokenness. - -MODULE SERVICES PROVIDED: - session _open_session and _close_session (blank) - -USAGE: - For the services you need resources limits (login for example) put a - the following line in /etc/pam.conf as the last line for that - service (usually after the pam_unix session line: - - login session required /lib/security/pam_limits.so - - Replace "login" for each service you are using this module, replace - "/lib/security" path with your real modules path. - -AUTHOR: - Cristian Gafton <gafton@redhat.com> - Thanks to Elliot Lee <sopwith@redhat.com> for his comments on - improving this module, and Jens Sorensen for Linux 2.4 updates. diff --git a/modules/pam_limits/limits.skel b/modules/pam_limits/limits.skel deleted file mode 100644 index ccb4e103..00000000 --- a/modules/pam_limits/limits.skel +++ /dev/null @@ -1,45 +0,0 @@ -# /etc/security/limits.conf -# -#Each line describes a limit for a user in the form: -# -#<domain> <type> <item> <value> -# -#Where: -#<domain> can be: -# - an user name -# - a group name, with @group syntax -# - the wildcard *, for default entry -# - the wildcard %, can be also used with %group syntax, -# for maxlogin limit -# -#<type> can have the two values: -# - "soft" for enforcing the soft limits -# - "hard" for enforcing hard limits -# -#<item> can be one of the following: -# - core - limits the core file size (KB) -# - data - max data size (KB) -# - fsize - maximum filesize (KB) -# - memlock - max locked-in-memory address space (KB) -# - nofile - max number of open files -# - rss - max resident set size (KB) -# - stack - max stack size (KB) -# - cpu - max CPU time (MIN) -# - nproc - max number of processes -# - as - address space limit -# - maxlogins - max number of logins for this user -# - priority - the priority to run user process with -# - locks - max number of file locks the user can hold -# -#<domain> <type> <item> <value> -# - -#* soft core 0 -#* hard rss 10000 -#@student hard nproc 20 -#@faculty soft nproc 20 -#@faculty hard nproc 50 -#ftp hard nproc 0 -#@student - maxlogins 4 - -# End of file diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c deleted file mode 100644 index 6837fdef..00000000 --- a/modules/pam_limits/pam_limits.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - * pam_limits - impose resource limits when opening a user session - * - * 1.6 - modified for PLD (added process priority settings) - * by Marcin Korzonek <mkorz@shadow.eu.org> - * 1.5 - Elliot Lee's "max system logins patch" - * 1.4 - addressed bug in configuration file parser - * 1.3 - modified the configuration file format - * 1.2 - added 'debug' and 'conf=' arguments - * 1.1 - added @group support - * 1.0 - initial release - Linux ONLY - * - * See end for Copyright information - */ - -#if !(defined(linux)) -#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! -#endif - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <errno.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/resource.h> - -#include <utmp.h> -#ifndef UT_USER /* some systems have ut_name instead of ut_user */ -#define UT_USER ut_user -#endif - -#include <grp.h> -#include <pwd.h> - -/* Module defines */ -#define LINE_LENGTH 1024 - -#define LIMITS_DEF_USER 0 /* limit was set by an user entry */ -#define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */ -#define LIMITS_DEF_DEFAULT 2 /* limit was set by an default entry */ -#define LIMITS_DEF_NONE 3 /* this limit was not set yet */ -#define LIMITS_DEF_ALL 4 /* limit was set by an default entry */ -#define LIMITS_DEF_ALLGROUP 5 /* limit was set by a group entry */ - -static const char *limits_def_names[] = { - "USER", - "GROUP", - "DEFAULT", - "NONE", - NULL, -}; - -struct user_limits_struct { - int src_soft; - int src_hard; - struct rlimit limit; -}; - -/* internal data */ -struct pam_limit_s { - int login_limit; /* the max logins limit */ - int login_limit_def; /* which entry set the login limit */ - int flag_numsyslogins; /* whether to limit logins only for a - specific user or to count all logins */ - int priority; /* the priority to run user process with */ - int supported[RLIM_NLIMITS]; - struct user_limits_struct limits[RLIM_NLIMITS]; - char conf_file[BUFSIZ]; - int utmp_after_pam_call; -}; - -#define LIMIT_LOGIN RLIM_NLIMITS+1 -#define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2 - -#define LIMIT_PRI RLIM_NLIMITS+3 - -#define LIMIT_SOFT 1 -#define LIMIT_HARD 2 - -#define PAM_SM_SESSION - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* logging */ -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("pam_limits", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 -#define PAM_DO_SETREUID 0x0002 -#define PAM_UTMP_EARLY 0x0004 - -static int _pam_parse(int argc, const char **argv, struct pam_limit_s *pl) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) { - ctrl |= PAM_DEBUG_ARG; - } else if (!strncmp(*argv,"conf=",5)) { - strncpy(pl->conf_file,*argv+5,sizeof(pl->conf_file)-1); - } else if (!strncmp(*argv,"change_uid",10)) { - ctrl |= PAM_DO_SETREUID; - } else if (!strcmp(*argv,"utmp_early")) { - ctrl |= PAM_UTMP_EARLY; - } else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - pl->conf_file[sizeof(pl->conf_file) - 1] = '\0'; - - return ctrl; -} - - -/* limits stuff */ -#ifdef DEFAULT_CONF_FILE -# define LIMITS_FILE DEFAULT_CONF_FILE -#else -# define LIMITS_FILE "/etc/security/limits.conf" -#endif - -#define LIMITED_OK 0 /* limit setting appeared to work */ -#define LIMIT_ERR 1 /* error setting a limit */ -#define LOGIN_ERR 2 /* too many logins err */ - -/* checks if a user is on a list of members of the GID 0 group */ -static int is_on_list(char * const *list, const char *member) -{ - while (*list) { - if (strcmp(*list, member) == 0) - return 1; - list++; - } - return 0; -} - -/* - * Checks if a user is a member of a group - return non-zero if - * the user is in the group. - */ -static int is_in_group(const char *user_name, const char *group_name) -{ - struct passwd *pwd; - struct group *grp, *pgrp; - char uname[LINE_LENGTH], gname[LINE_LENGTH]; - - if (!user_name || !strlen(user_name)) - return 0; - if (!group_name || !strlen(group_name)) - return 0; - memset(uname, 0, sizeof(uname)); - strncpy(uname, user_name, sizeof(uname)-1); - memset(gname, 0, sizeof(gname)); - strncpy(gname, group_name, sizeof(gname)-1); - - pwd = getpwnam(uname); - if (!pwd) - return 0; - - /* the info about this group */ - grp = getgrnam(gname); - if (!grp) - return 0; - - /* first check: is a member of the group_name group ? */ - if (is_on_list(grp->gr_mem, uname)) - return 1; - - /* next check: user primary group is group_name ? */ - pgrp = getgrgid(pwd->pw_gid); - if (!pgrp) - return 0; - if (!strcmp(pgrp->gr_name, gname)) - return 1; - - return 0; -} - -/* Counts the number of user logins and check against the limit*/ -static int check_logins(const char *name, int limit, int ctrl, - struct pam_limit_s *pl) -{ - struct utmp *ut; - unsigned int count; - - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "checking logins for '%s' (maximum of %d)\n", - name, limit); - } - - if (limit < 0) - return 0; /* no limits imposed */ - if (limit == 0) /* maximum 0 logins ? */ { - _pam_log(LOG_WARNING, "No logins allowed for '%s'\n", name); - return LOGIN_ERR; - } - - setutent(); - - /* Because there is no definition about when an application - actually adds a utmp entry, some applications bizarrely do the - utmp call before the have PAM authenticate them to the system: - you're logged it, sort of...? Anyway, you can use the - "utmp_early" module argument in your PAM config file to make - allowances for this sort of problem. (There should be a PAM - standard for this, since if a module wants to actually map a - username then any early utmp entry will be for the unmapped - name = broken.) */ - - if (ctrl & PAM_UTMP_EARLY) { - count = 0; - } else { - count = 1; - } - - while((ut = getutent())) { -#ifdef USER_PROCESS - if (ut->ut_type != USER_PROCESS) { - continue; - } -#endif - if (ut->UT_USER[0] == '\0') { - continue; - } - if (!pl->flag_numsyslogins) { - if (((pl->login_limit_def == LIMITS_DEF_USER) - || (pl->login_limit_def == LIMITS_DEF_GROUP) - || (pl->login_limit_def == LIMITS_DEF_DEFAULT)) - && strncmp(name, ut->UT_USER, sizeof(ut->UT_USER)) != 0) { - continue; - } - if ((pl->login_limit_def == LIMITS_DEF_ALLGROUP) - && !is_in_group(ut->UT_USER, name)) { - continue; - } - } - if (++count > limit) { - break; - } - } - endutent(); - if (count > limit) { - if (name) { - _pam_log(LOG_WARNING, "Too many logins (max %d) for %s", - limit, name); - } else { - _pam_log(LOG_WARNING, "Too many system logins (max %d)", limit); - } - return LOGIN_ERR; - } - return 0; -} - -static int init_limits(struct pam_limit_s *pl) -{ - int i; - int retval = PAM_SUCCESS; - - D(("called.")); - - for(i = 0; i < RLIM_NLIMITS; i++) { - int r = getrlimit(i, &pl->limits[i].limit); - if (r == -1) { - if (errno == EINVAL) { - pl->supported[i] = 0; - } else { - retval = !PAM_SUCCESS; - } - } else { - pl->supported[i] = 1; - pl->limits[i].src_soft = LIMITS_DEF_NONE; - pl->limits[i].src_hard = LIMITS_DEF_NONE; - } - } - - pl->priority = 0; - pl->login_limit = -2; - pl->login_limit_def = LIMITS_DEF_NONE; - - return retval; -} - -static void process_limit(int source, const char *lim_type, - const char *lim_item, const char *lim_value, - int ctrl, struct pam_limit_s *pl) -{ - int limit_item; - int limit_type = 0; - long limit_value; - const char **endptr = &lim_value; - const char *value_orig = lim_value; - - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "%s: processing %s %s %s for %s\n", - __FUNCTION__,lim_type,lim_item,lim_value, - limits_def_names[source]); - - if (strcmp(lim_item, "cpu") == 0) - limit_item = RLIMIT_CPU; - else if (strcmp(lim_item, "fsize") == 0) - limit_item = RLIMIT_FSIZE; - else if (strcmp(lim_item, "data") == 0) - limit_item = RLIMIT_DATA; - else if (strcmp(lim_item, "stack") == 0) - limit_item = RLIMIT_STACK; - else if (strcmp(lim_item, "core") == 0) - limit_item = RLIMIT_CORE; - else if (strcmp(lim_item, "rss") == 0) - limit_item = RLIMIT_RSS; - else if (strcmp(lim_item, "nproc") == 0) - limit_item = RLIMIT_NPROC; - else if (strcmp(lim_item, "nofile") == 0) - limit_item = RLIMIT_NOFILE; - else if (strcmp(lim_item, "memlock") == 0) - limit_item = RLIMIT_MEMLOCK; - else if (strcmp(lim_item, "as") == 0) - limit_item = RLIMIT_AS; -#ifdef RLIMIT_LOCKS - else if (strcmp(lim_item, "locks") == 0) - limit_item = RLIMIT_LOCKS; -#endif - else if (strcmp(lim_item, "maxlogins") == 0) { - limit_item = LIMIT_LOGIN; - pl->flag_numsyslogins = 0; - } else if (strcmp(lim_item, "maxsyslogins") == 0) { - limit_item = LIMIT_NUMSYSLOGINS; - pl->flag_numsyslogins = 1; - } else if (strcmp(lim_item, "priority") == 0) { - limit_item = LIMIT_PRI; - } else { - _pam_log(LOG_DEBUG,"unknown limit item '%s'", lim_item); - return; - } - - if (strcmp(lim_type,"soft")==0) - limit_type=LIMIT_SOFT; - else if (strcmp(lim_type, "hard")==0) - limit_type=LIMIT_HARD; - else if (strcmp(lim_type,"-")==0) - limit_type=LIMIT_SOFT | LIMIT_HARD; - else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) { - _pam_log(LOG_DEBUG,"unknown limit type '%s'", lim_type); - return; - } - - /* - * there is a warning here because the library prototype for this - * function is incorrect. - */ - limit_value = strtol(lim_value, endptr, 10); - - /* special case value when limiting logins */ - if (limit_value == 0 && value_orig == *endptr) { /* no chars read */ - if (strcmp(lim_value,"-") != 0) { - _pam_log(LOG_DEBUG,"wrong limit value '%s'", lim_value); - return; - } else - if (limit_item != LIMIT_LOGIN) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, - "'-' limit value valid for maxlogins type only"); - return; - } else - limit_value = -1; - } - - /* one more special case when limiting logins */ - if ((source == LIMITS_DEF_ALL || source == LIMITS_DEF_ALLGROUP) - && (limit_item != LIMIT_LOGIN)) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, - "'%%' domain valid for maxlogins type only"); - return; - } - - switch(limit_item) { - case RLIMIT_CPU: - limit_value *= 60; - break; - case RLIMIT_FSIZE: - case RLIMIT_DATA: - case RLIMIT_STACK: - case RLIMIT_CORE: - case RLIMIT_RSS: - case RLIMIT_MEMLOCK: - case RLIMIT_AS: - limit_value *= 1024; - break; - } - - if ( (limit_item != LIMIT_LOGIN) - && (limit_item != LIMIT_NUMSYSLOGINS) - && (limit_item != LIMIT_PRI) ) { - if (limit_type & LIMIT_SOFT) { - if (pl->limits[limit_item].src_soft < source) { - return; - } else { - pl->limits[limit_item].limit.rlim_cur = limit_value; - pl->limits[limit_item].src_soft = source; - } - } - if (limit_type & LIMIT_HARD) { - if (pl->limits[limit_item].src_hard < source) { - return; - } else { - pl->limits[limit_item].limit.rlim_max = limit_value; - pl->limits[limit_item].src_hard = source; - } - } - } else { - /* recent kernels support negative priority limits (=raise priority) */ - - if (limit_item == LIMIT_PRI) { - pl->priority = limit_value; - } else { - if (pl->login_limit_def < source) { - return; - } else { - pl->login_limit = limit_value; - pl->login_limit_def = source; - } - } - } - return; -} - -static int parse_config_file(const char *uname, int ctrl, - struct pam_limit_s *pl) -{ - FILE *fil; - char buf[LINE_LENGTH]; - -#define CONF_FILE (pl->conf_file[0])?pl->conf_file:LIMITS_FILE - /* check for the LIMITS_FILE */ - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG,"reading settings from '%s'", CONF_FILE); - fil = fopen(CONF_FILE, "r"); - if (fil == NULL) { - _pam_log (LOG_WARNING, "can not read settings from %s", CONF_FILE); - return PAM_SERVICE_ERR; - } -#undef CONF_FILE - - /* init things */ - memset(buf, 0, sizeof(buf)); - /* start the show */ - while (fgets(buf, LINE_LENGTH, fil) != NULL) { - char domain[LINE_LENGTH]; - char ltype[LINE_LENGTH]; - char item[LINE_LENGTH]; - char value[LINE_LENGTH]; - int i,j; - char *tptr; - - tptr = buf; - /* skip the leading white space */ - while (*tptr && isspace(*tptr)) - tptr++; - strncpy(buf, tptr, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - - /* Rip off the comments */ - tptr = strchr(buf,'#'); - if (tptr) - *tptr = '\0'; - /* Rip off the newline char */ - tptr = strchr(buf,'\n'); - if (tptr) - *tptr = '\0'; - /* Anything left ? */ - if (!strlen(buf)) { - memset(buf, 0, sizeof(buf)); - continue; - } - - memset(domain, 0, sizeof(domain)); - memset(ltype, 0, sizeof(ltype)); - memset(item, 0, sizeof(item)); - memset(value, 0, sizeof(value)); - - i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value); - D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]", - i, domain, ltype, item, value)); - - for(j=0; j < strlen(domain); j++) - domain[j]=tolower(domain[j]); - for(j=0; j < strlen(ltype); j++) - ltype[j]=tolower(ltype[j]); - for(j=0; j < strlen(item); j++) - item[j]=tolower(item[j]); - for(j=0; j < strlen(value); j++) - value[j]=tolower(value[j]); - - if (i == 4) { /* a complete line */ - if (strcmp(uname, domain) == 0) /* this user have a limit */ - process_limit(LIMITS_DEF_USER, ltype, item, value, ctrl, pl); - else if (domain[0]=='@') { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "checking if %s is in group %s", - uname, domain + 1); - } - if (is_in_group(uname, domain+1)) - process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl, - pl); - } else if (domain[0]=='%') { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "checking if %s is in group %s", - uname, domain + 1); - } - if (strcmp(domain,"%") == 0) - process_limit(LIMITS_DEF_ALL, ltype, item, value, ctrl, - pl); - else if (is_in_group(uname, domain+1)) - process_limit(LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, - pl); - } else if (strcmp(domain, "*") == 0) - process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, - pl); - } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */ - if (strcmp(uname, domain) == 0) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "no limits for '%s'", uname); - } - fclose(fil); - return PAM_IGNORE; - } else if (domain[0] == '@' && is_in_group(uname, domain+1)) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "no limits for '%s' in group '%s'", - uname, domain+1); - } - fclose(fil); - return PAM_IGNORE; - } - } else { - _pam_log(LOG_DEBUG,"invalid line '%s' - skipped", buf); - } - } - fclose(fil); - return PAM_SUCCESS; -} - -static int setup_limits(const char * uname, uid_t uid, int ctrl, - struct pam_limit_s *pl) -{ - int i; - int status; - int retval = LIMITED_OK; - - if (uid == 0) { - /* do not impose limits (+ve limits anyway) on the superuser */ - if (pl->priority > 0) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "user '%s' has UID 0 - no limits imposed", - uname); - } - pl->priority = 0; - } - } - - for (i=0, status=LIMITED_OK; i<RLIM_NLIMITS; i++) { - if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max) - pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max; - if (!pl->supported[i]) { - /* skip it if its not known to the system */ - continue; - } - status |= setrlimit(i, &pl->limits[i].limit); - } - - if (status) { - retval = LIMIT_ERR; - } - - status = setpriority(PRIO_PROCESS, 0, pl->priority); - if (status != 0) { - retval = LIMIT_ERR; - } - - if (uid == 0) { - D(("skip login limit check for uid=0")); - } else if (pl->login_limit > 0) { - if (check_logins(uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) { - retval |= LOGIN_ERR; - } - } else if (pl->login_limit == 0) { - retval |= LOGIN_ERR; - } - - return retval; -} - -/* now the session stuff */ -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval; - char *user_name; - struct passwd *pwd; - int ctrl; - struct pam_limit_s pl; - - D(("called.")); - - memset(&pl, 0, sizeof(pl)); - - ctrl = _pam_parse(argc, argv, &pl); - retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); - if ( user_name == NULL || retval != PAM_SUCCESS ) { - _pam_log(LOG_CRIT, "open_session - error recovering username"); - return PAM_SESSION_ERR; - } - - pwd = getpwnam(user_name); - if (!pwd) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_WARNING, "open_session username '%s' does not exist", - user_name); - return PAM_SESSION_ERR; - } - - retval = init_limits(&pl); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_WARNING, "cannot initialize"); - return PAM_IGNORE; - } - - retval = parse_config_file(pwd->pw_name, ctrl, &pl); - if (retval == PAM_IGNORE) { - D(("the configuration file has an applicable '<domain> -' entry")); - return PAM_SUCCESS; - } - if (retval != PAM_SUCCESS) { - _pam_log(LOG_WARNING, "error parsing the configuration file"); - return PAM_IGNORE; - } - - if (ctrl & PAM_DO_SETREUID) { - setreuid(pwd->pw_uid, -1); - } - retval = setup_limits(pwd->pw_name, pwd->pw_uid, ctrl, &pl); - if (retval != LIMITED_OK) { - return PAM_PERM_DENIED; - } - - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - /* nothing to do */ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_limits_modstruct = { - "pam_limits", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL -}; -#endif - -/* - * Copyright (c) Cristian Gafton, 1996-1997, <gafton@redhat.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_listfile/.cvsignore b/modules/pam_listfile/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_listfile/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_listfile/Makefile b/modules/pam_listfile/Makefile deleted file mode 100644 index 18315256..00000000 --- a/modules/pam_listfile/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_listfile - -include ../Simple.Rules diff --git a/modules/pam_listfile/README b/modules/pam_listfile/README deleted file mode 100644 index b65e7dbb..00000000 --- a/modules/pam_listfile/README +++ /dev/null @@ -1,25 +0,0 @@ -SUMMARY: - pam_listfile: - Checks a specified item against a list in a file. - Options: - * item=[tty|user|rhost|ruser|group|shell] - * sense=[allow|deny] (action to take if found in file, - if the item is NOT found in the file, then - the opposite action is requested) - * file=/the/file/to/get/the/list/from - * onerr=[succeed|fail] (if something weird happens - such as unable to open the file, what to do?) - * apply=[user|@group] - restrict the user class for which the restriction - apply. Note that with item=[user|ruser|group] this - does not make sense, but for item=[tty|rhost|shell] - it have a meaning. (Cristian Gafton) - - Also checks to make sure that the list file is a plain - file and not world writable. - - - Elliot Lee <sopwith@redhat.com>, Red Hat Software. - v0.9 August 16, 1996. - -BUGS: - Bugs? diff --git a/modules/pam_listfile/pam_listfile.c b/modules/pam_listfile/pam_listfile.c deleted file mode 100644 index b560b4b6..00000000 --- a/modules/pam_listfile/pam_listfile.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * $Id$ - * - */ - -/* - * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996. - * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11 - * - * This code began life as the pam_rootok module. - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <syslog.h> -#include <stdarg.h> -#include <string.h> -#include <pwd.h> -#include <grp.h> - -#ifdef DEBUG -#include <assert.h> -#endif - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* some syslogging */ - -#define LOCAL_LOG_PREFIX "PAM-listfile: " - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - vsyslog(LOG_AUTH | err, format, args); - va_end(args); -} - -/* checks if a user is on a list of members */ -static int is_on_list(char * const *list, const char *member) -{ - while (*list) { - if (strcmp(*list, member) == 0) - return 1; - list++; - } - return 0; -} - -/* Checks if a user is a member of a group */ -static int is_on_group(const char *user_name, const char *group_name) -{ - struct passwd *pwd; - struct group *grp, *pgrp; - char uname[BUFSIZ], gname[BUFSIZ]; - - if (!strlen(user_name)) - return 0; - if (!strlen(group_name)) - return 0; - bzero(uname, sizeof(uname)); - strncpy(uname, user_name, sizeof(uname)-1); - bzero(gname, sizeof(gname)); - strncpy(gname, group_name, sizeof(gname)-1); - - pwd = getpwnam(uname); - if (!pwd) - return 0; - - /* the info about this group */ - grp = getgrnam(gname); - if (!grp) - return 0; - - /* first check: is a member of the group_name group ? */ - if (is_on_list(grp->gr_mem, uname)) - return 1; - - /* next check: user primary group is group_name ? */ - pgrp = getgrgid(pwd->pw_gid); - if (!pgrp) - return 0; - if (!strcmp(pgrp->gr_name, gname)) - return 1; - - return 0; -} - -/* --- authentication management functions (only) --- */ - -/* Extended Items that are not directly available via pam_get_item() */ -#define EI_GROUP (1 << 0) -#define EI_SHELL (1 << 1) - -/* Constants for apply= parameter */ -#define APPLY_TYPE_NULL 0 -#define APPLY_TYPE_NONE 1 -#define APPLY_TYPE_USER 2 -#define APPLY_TYPE_GROUP 3 - -#define LESSER(a, b) ((a) < (b) ? (a) : (b)) - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) -{ - int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2; - const char *citemp; - char *ifname=NULL; - char aline[256]; - char mybuf[256],myval[256]; - struct stat fileinfo; - FILE *inf; - char apply_val[256]; - int apply_type; - - /* Stuff for "extended" items */ - struct passwd *userinfo; - struct group *grpinfo; - char *itemlist[256]; /* Maximum of 256 items */ - - D(("called.")); - - apply_type=APPLY_TYPE_NULL; - memset(apply_val,0,sizeof(apply_val)); - - for(i=0; i < argc; i++) { - { - const char *junk; - - memset(mybuf,'\0',sizeof(mybuf)); - memset(myval,'\0',sizeof(mybuf)); - junk = strchr(argv[i], '='); - if((junk == NULL) || (junk - argv[i]) >= sizeof(mybuf)) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Bad option: \"%s\"", - argv[i]); - continue; - } - strncpy(mybuf, argv[i], LESSER(junk - argv[i], sizeof(mybuf) - 1)); - strncpy(myval, junk + 1, sizeof(myval) - 1); - } - if(!strcmp(mybuf,"onerr")) - if(!strcmp(myval,"succeed")) - onerr = PAM_SUCCESS; - else if(!strcmp(myval,"fail")) - onerr = PAM_SERVICE_ERR; - else - return PAM_SERVICE_ERR; - else if(!strcmp(mybuf,"sense")) - if(!strcmp(myval,"allow")) - sense=0; - else if(!strcmp(myval,"deny")) - sense=1; - else - return onerr; - else if(!strcmp(mybuf,"file")) { - ifname = (char *)malloc(strlen(myval)+1); - strcpy(ifname,myval); - } else if(!strcmp(mybuf,"item")) - if(!strcmp(myval,"user")) - citem = PAM_USER; - else if(!strcmp(myval,"tty")) - citem = PAM_TTY; - else if(!strcmp(myval,"rhost")) - citem = PAM_RHOST; - else if(!strcmp(myval,"ruser")) - citem = PAM_RUSER; - else { /* These items are related to the user, but are not - directly gettable with pam_get_item */ - citem = PAM_USER; - if(!strcmp(myval,"group")) - extitem = EI_GROUP; - else if(!strcmp(myval,"shell")) - extitem = EI_SHELL; - else - citem = 0; - } else if(!strcmp(mybuf,"apply")) { - apply_type=APPLY_TYPE_NONE; - memset(apply_val,'\0',sizeof(apply_val)); - if (myval[0]=='@') { - apply_type=APPLY_TYPE_GROUP; - strncpy(apply_val,myval+1,sizeof(apply_val)-1); - } else { - apply_type=APPLY_TYPE_USER; - strncpy(apply_val,myval,sizeof(apply_val)-1); - } - } else { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Unknown option: %s",mybuf); - return onerr; - } - } - - if(!citem) { - _pam_log(LOG_ERR, - LOCAL_LOG_PREFIX "Unknown item or item not specified"); - return onerr; - } else if(!ifname) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "List filename not specified"); - return onerr; - } else if(sense == 2) { - _pam_log(LOG_ERR, - LOCAL_LOG_PREFIX "Unknown sense or sense not specified"); - return onerr; - } else if( - (apply_type==APPLY_TYPE_NONE) || - ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0')) - ) { - _pam_log(LOG_ERR, - LOCAL_LOG_PREFIX "Invalid usage for apply= parameter"); - return onerr; - } - - /* Check if it makes sense to use the apply= parameter */ - if (apply_type != APPLY_TYPE_NULL) { - if((citem==PAM_USER) || (citem==PAM_RUSER)) { - _pam_log(LOG_WARNING, - LOCAL_LOG_PREFIX "Non-sense use for apply= parameter"); - apply_type=APPLY_TYPE_NULL; - } - if(extitem && (extitem==EI_GROUP)) { - _pam_log(LOG_WARNING, - LOCAL_LOG_PREFIX "Non-sense use for apply= parameter"); - apply_type=APPLY_TYPE_NULL; - } - } - - /* Short-circuit - test if this session apply for this user */ - { - const char *user_name; - int rval; - - rval=pam_get_user(pamh,&user_name,NULL); - if((rval==PAM_SUCCESS) && user_name[0]) { - /* Got it ? Valid ? */ - if(apply_type==APPLY_TYPE_USER) { - if(strcmp(user_name, apply_val)) { - /* Does not apply to this user */ -#ifdef DEBUG - _pam_log(LOG_DEBUG, - LOCAL_LOG_PREFIX "don't apply: apply=%s, user=%s", - apply_val,user_name); -#endif /* DEBUG */ - return PAM_IGNORE; - } - } else if(apply_type==APPLY_TYPE_GROUP) { - if(!is_on_group(user_name,apply_val)) { - /* Not a member of apply= group */ -#ifdef DEBUG - _pam_log(LOG_DEBUG, - LOCAL_LOG_PREFIX - "don't apply: %s not a member of group %s", - user_name,apply_val); -#endif /* DEBUG */ - return PAM_IGNORE; - } - } - } - } - - retval = pam_get_item(pamh,citem,(const void **)&citemp); - if(retval != PAM_SUCCESS) { - return onerr; - } - if((citem == PAM_USER) && !citemp) { - pam_get_user(pamh,&citemp,NULL); - if (retval != PAM_SUCCESS) - return PAM_SERVICE_ERR; - } - - if(!citemp || (strlen(citemp) <= 0)) { - /* The item was NULL - we are sure not to match */ - return sense?PAM_SUCCESS:PAM_AUTH_ERR; - } - - if(extitem) { - switch(extitem) { - case EI_GROUP: - userinfo = getpwnam(citemp); - if (userinfo == NULL) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", - citemp); - return onerr; - } - grpinfo = getgrgid(userinfo->pw_gid); - if (grpinfo == NULL) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getgrgid(%d) failed", - (int)userinfo->pw_gid); - return onerr; - } - itemlist[0] = x_strdup(grpinfo->gr_name); - setgrent(); - for (i=1; (i < sizeof(itemlist)/sizeof(itemlist[0])-1) && - (grpinfo = getgrent()); ) { - if (is_on_list(grpinfo->gr_mem,citemp)) { - itemlist[i++] = x_strdup(grpinfo->gr_name); - } - } - endgrent(); - itemlist[i] = NULL; - break; - case EI_SHELL: - /* Assume that we have already gotten PAM_USER in - pam_get_item() - a valid assumption since citem - gets set to PAM_USER in the extitem switch */ - userinfo = getpwnam(citemp); - if (userinfo == NULL) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", - citemp); - return onerr; - } - citemp = userinfo->pw_shell; - break; - default: - _pam_log(LOG_ERR, - LOCAL_LOG_PREFIX - "Internal weirdness, unknown extended item %d", - extitem); - return onerr; - } - } -#ifdef DEBUG - _pam_log(LOG_INFO, - LOCAL_LOG_PREFIX - "Got file = %s, item = %d, value = %s, sense = %d", - ifname, citem, citemp, sense); -#endif - if(lstat(ifname,&fileinfo)) { - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Couldn't open %s",ifname); - return onerr; - } - - if((fileinfo.st_mode & S_IWOTH) - || !S_ISREG(fileinfo.st_mode)) { - /* If the file is world writable or is not a - normal file, return error */ - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX - "%s is either world writable or not a normal file", - ifname); - return PAM_AUTH_ERR; - } - - inf = fopen(ifname,"r"); - if(inf == NULL) { /* Check that we opened it successfully */ - if (onerr == PAM_SERVICE_ERR) { - /* Only report if it's an error... */ - _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Error opening %s", ifname); - } - return onerr; - } - /* There should be no more errors from here on */ - retval=PAM_AUTH_ERR; - /* This loop assumes that PAM_SUCCESS == 0 - and PAM_AUTH_ERR != 0 */ -#ifdef DEBUG - assert(PAM_SUCCESS == 0); - assert(PAM_AUTH_ERR != 0); -#endif - if(extitem == EI_GROUP) { - while((fgets(aline,255,inf) != NULL) - && retval) { - if(aline[strlen(aline) - 1] == '\n') - aline[strlen(aline) - 1] = '\0'; - for(i=0;itemlist[i];) - /* If any of the items match, strcmp() == 0, and we get out - of this loop */ - retval = (strcmp(aline,itemlist[i++]) && retval); - } - for(i=0;itemlist[i];) - free(itemlist[i++]); - } else { - while((fgets(aline,255,inf) != NULL) - && retval) { - if(aline[strlen(aline) - 1] == '\n') - aline[strlen(aline) - 1] = '\0'; - retval = strcmp(aline,citemp); - } - } - fclose(inf); - free(ifname); - if ((sense && retval) || (!sense && !retval)) { -#ifdef DEBUG - _pam_log(LOG_INFO, LOCAL_LOG_PREFIX - "Returning PAM_SUCCESS, retval = %d", retval); -#endif - return PAM_SUCCESS; - } - else { - const char *service, *user_name; -#ifdef DEBUG - _pam_log(LOG_INFO,LOCAL_LOG_PREFIX - "Returning PAM_AUTH_ERR, retval = %d", retval); -#endif - (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); - (void) pam_get_user(pamh, &user_name, NULL); - _pam_log(LOG_ALERT,LOCAL_LOG_PREFIX "Refused user %s for service %s", - user_name, service); - return PAM_AUTH_ERR; - } -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) -{ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_listfile_modstruct = { - "pam_listfile", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ - diff --git a/modules/pam_mail/.cvsignore b/modules/pam_mail/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_mail/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_mail/Makefile b/modules/pam_mail/Makefile deleted file mode 100644 index 93ca429b..00000000 --- a/modules/pam_mail/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_mail - -include ../Simple.Rules diff --git a/modules/pam_mail/README b/modules/pam_mail/README deleted file mode 100644 index 155bd1db..00000000 --- a/modules/pam_mail/README +++ /dev/null @@ -1,17 +0,0 @@ -This is the README for pam_mail -------------------------------- - -This PAM module tells the User that he has new/unread email. - -Options for: -auth: for authentication it provides pam_authenticate() and - pam_setcred() hooks. - - "debug" write more information to syslog - "dir=maildir" users mailbox is maildir/<login> - "hash=count" mail directory hash depth - "close" print message also on logout - "nopen" print message not on login - "noenv" don't set the MAIL environment variable - "empty" also print message if user has no mail - diff --git a/modules/pam_mail/pam_mail.c b/modules/pam_mail/pam_mail.c deleted file mode 100644 index 35a6b9f2..00000000 --- a/modules/pam_mail/pam_mail.c +++ /dev/null @@ -1,499 +0,0 @@ -/* pam_mail module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 - * $HOME additions by David Kinchlea <kinch@kinch.ark.com> 1997/1/7 - * mailhash additions by Chris Adams <cadams@ro.com> 1998/7/11 - */ - -#include <security/_pam_aconf.h> - -#include <ctype.h> -#include <pwd.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <dirent.h> - -#ifdef WANT_PWDB -#include <pwdb/pwdb_public.h> -#endif - -#define DEFAULT_MAIL_DIRECTORY PAM_PATH_MAILDIR -#define MAIL_FILE_FORMAT "%s%s/%s" -#define MAIL_ENV_NAME "MAIL" -#define MAIL_ENV_FORMAT MAIL_ENV_NAME "=%s" -#define YOUR_MAIL_VERBOSE_FORMAT "You have %s mail in %s." -#define YOUR_MAIL_STANDARD_FORMAT "You have %smail." -#define NO_MAIL_STANDARD_FORMAT "No mail." - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_SESSION -#define PAM_SM_AUTH - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* some syslogging */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-mail", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 -#define PAM_NO_LOGIN 0x0002 -#define PAM_LOGOUT_TOO 0x0004 -#define PAM_NEW_MAIL_DIR 0x0010 -#define PAM_MAIL_SILENT 0x0020 -#define PAM_NO_ENV 0x0040 -#define PAM_HOME_MAIL 0x0100 -#define PAM_EMPTY_TOO 0x0200 -#define PAM_STANDARD_MAIL 0x0400 -#define PAM_QUIET_MAIL 0x1000 - -static int _pam_parse(int flags, int argc, const char **argv, char **maildir, - int *hashcount) -{ - int ctrl=0; - - if (flags & PAM_SILENT) { - ctrl |= PAM_MAIL_SILENT; - } - - *hashcount = 0; - - /* step through arguments */ - for (; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strcmp(*argv,"quiet")) - ctrl |= PAM_QUIET_MAIL; - else if (!strcmp(*argv,"standard")) - ctrl |= PAM_STANDARD_MAIL | PAM_EMPTY_TOO; - else if (!strncmp(*argv,"dir=",4)) { - *maildir = x_strdup(4+*argv); - if (*maildir != NULL) { - D(("new mail directory: %s", *maildir)); - ctrl |= PAM_NEW_MAIL_DIR; - } else { - _log_err(LOG_CRIT, - "failed to duplicate mail directory - ignored"); - } - } else if (!strncmp(*argv,"hash=",5)) { - char *ep = NULL; - *hashcount = strtol(*argv+5,&ep,10); - if (!ep || (*hashcount < 0)) { - *hashcount = 0; - } - } else if (!strcmp(*argv,"close")) { - ctrl |= PAM_LOGOUT_TOO; - } else if (!strcmp(*argv,"nopen")) { - ctrl |= PAM_NO_LOGIN; - } else if (!strcmp(*argv,"noenv")) { - ctrl |= PAM_NO_ENV; - } else if (!strcmp(*argv,"empty")) { - ctrl |= PAM_EMPTY_TOO; - } else { - _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - if ((*hashcount != 0) && !(ctrl & PAM_NEW_MAIL_DIR)) { - *maildir = x_strdup(DEFAULT_MAIL_DIRECTORY); - ctrl |= PAM_NEW_MAIL_DIR; - } - - return ctrl; -} - -/* a front end for conversations */ - -static int converse(pam_handle_t *pamh, int ctrl, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { - - retval = conv->conv(nargs, ( const struct pam_message ** ) message - , response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && (PAM_DEBUG_ARG & ctrl) ) { - _log_err(LOG_DEBUG, "conversation failure [%s]" - , pam_strerror(pamh, retval)); - } - - } else { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - , pam_strerror(pamh, retval)); - } - - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -static int get_folder(pam_handle_t *pamh, int ctrl, - char **path_mail, char **folder_p, int hashcount) -{ - int retval; - const char *user, *path; - char *folder; - const struct passwd *pwd=NULL; - - retval = pam_get_user(pamh, &user, NULL); - if (retval != PAM_SUCCESS || user == NULL) { - _log_err(LOG_ERR, "no user specified"); - return PAM_USER_UNKNOWN; - } - - if (ctrl & PAM_NEW_MAIL_DIR) { - path = *path_mail; - if (*path == '~') { /* support for $HOME delivery */ - pwd = getpwnam(user); - if (pwd == NULL) { - _log_err(LOG_ERR, "user [%s] unknown", user); - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); - return PAM_USER_UNKNOWN; - } - /* - * "~/xxx" and "~xxx" are treated as same - */ - if (!*++path || (*path == '/' && !*++path)) { - _log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail); - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); - return PAM_ABORT; - } - ctrl |= PAM_HOME_MAIL; - if (hashcount != 0) { - _log_err(LOG_ALERT, "can't do hash= and home directory mail"); - } - } - } else { - path = DEFAULT_MAIL_DIRECTORY; - } - - /* put folder together */ - - if (ctrl & PAM_HOME_MAIL) { - folder = malloc(sizeof(MAIL_FILE_FORMAT) - +strlen(pwd->pw_dir)+strlen(path)); - } else { - folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user) - +2*hashcount); - } - - if (folder != NULL) { - if (ctrl & PAM_HOME_MAIL) { - sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path); - } else { - int i; - char *hash = malloc(2*hashcount+1); - - if (hash) { - for (i = 0; i < hashcount; i++) { - hash[2*i] = '/'; - hash[2*i+1] = user[i]; - } - hash[2*i] = '\0'; - sprintf(folder, MAIL_FILE_FORMAT, path, hash, user); - _pam_overwrite(hash); - _pam_drop(hash); - } else { - sprintf(folder, "error"); - } - } - D(("folder =[%s]", folder)); - } - - /* tidy up */ - - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); - user = NULL; - - if (folder == NULL) { - _log_err(LOG_CRIT, "out of memory for mail folder"); - return PAM_BUF_ERR; - } - - *folder_p = folder; - folder = NULL; - - return PAM_SUCCESS; -} - -static const char *get_mail_status(int ctrl, const char *folder) -{ - const char *type = NULL; - static char dir[256]; - struct stat mail_st; - struct dirent **namelist; - int i; - - if (stat(folder, &mail_st) == 0) { - if (S_ISDIR(mail_st.st_mode)) { /* Assume Maildir format */ - sprintf(dir, "%.250s/new", folder); - i = scandir(dir, &namelist, 0, alphasort); - if (i > 2) { - type = "new"; - while (--i) - free(namelist[i]); - } else { - while (--i >= 0) - free(namelist[i]); - sprintf(dir, "%.250s/cur", folder); - i = scandir(dir, &namelist, 0, alphasort); - if (i > 2) { - type = "old"; - while (--i) - free(namelist[i]); - } else if (ctrl & PAM_EMPTY_TOO) { - while (--i >= 0) - free(namelist[i]); - type = "no"; - } else { - type = NULL; - } - } - } else { - if (mail_st.st_size > 0) { - if (mail_st.st_atime < mail_st.st_mtime) /* new */ - type = (ctrl & PAM_STANDARD_MAIL) ? "new " : "new"; - else /* old */ - type = (ctrl & PAM_STANDARD_MAIL) ? "" : "old"; - } else if (ctrl & PAM_EMPTY_TOO) { - type = "no"; - } else { - type = NULL; - } - } - } - - memset(dir, 0, 256); - memset(&mail_st, 0, sizeof(mail_st)); - D(("user has %s mail in %s folder", type, folder)); - return type; -} - -static int report_mail(pam_handle_t *pamh, int ctrl - , const char *type, const char *folder) -{ - int retval; - - if (!(ctrl & PAM_MAIL_SILENT) || ((ctrl & PAM_QUIET_MAIL) && strcmp(type, "new"))) { - char *remark; - - if (ctrl & PAM_STANDARD_MAIL) - if (!strcmp(type, "no")) - remark = malloc(strlen(NO_MAIL_STANDARD_FORMAT)+1); - else - remark = malloc(strlen(YOUR_MAIL_STANDARD_FORMAT)+strlen(type)+1); - else - remark = malloc(strlen(YOUR_MAIL_VERBOSE_FORMAT)+strlen(type)+strlen(folder)+1); - if (remark == NULL) { - retval = PAM_BUF_ERR; - } else { - struct pam_message msg[1], *mesg[1]; - struct pam_response *resp=NULL; - - if (ctrl & PAM_STANDARD_MAIL) - if (!strcmp(type, "no")) - sprintf(remark, NO_MAIL_STANDARD_FORMAT); - else - sprintf(remark, YOUR_MAIL_STANDARD_FORMAT, type); - else - sprintf(remark, YOUR_MAIL_VERBOSE_FORMAT, type, folder); - - mesg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = remark; - - retval = converse(pamh, ctrl, 1, mesg, &resp); - - _pam_overwrite(remark); - _pam_drop(remark); - if (resp) - _pam_drop_reply(resp, 1); - } - } else { - D(("keeping quiet")); - retval = PAM_SUCCESS; - } - - D(("returning %s", pam_strerror(pamh, retval))); - return retval; -} - -static int _do_mail(pam_handle_t *, int, int, const char **, int); - -/* --- authentication functions --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc, - const char **argv) -{ - return PAM_IGNORE; -} - -/* Checking mail as part of authentication */ -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - if (!(flags & (PAM_ESTABLISH_CRED|PAM_DELETE_CRED))) - return PAM_IGNORE; - return _do_mail(pamh,flags,argc,argv,(flags & PAM_ESTABLISH_CRED)); -} - -/* --- session management functions --- */ - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return _do_mail(pamh,flags,argc,argv,0);; -} - -/* Checking mail as part of the session management */ -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return _do_mail(pamh,flags,argc,argv,1); -} - - -/* --- The Beaf (Tm) --- */ - -static int _do_mail(pam_handle_t *pamh, int flags, int argc, - const char **argv, int est) -{ - int retval, ctrl, hashcount; - char *path_mail=NULL, *folder; - const char *type; - - /* - * this module (un)sets the MAIL environment variable, and checks if - * the user has any new mail. - */ - - ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount); - - /* Do we have anything to do? */ - - if (flags & PAM_SILENT) - return PAM_SUCCESS; - - /* which folder? */ - - retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount); - if (retval != PAM_SUCCESS) { - D(("failed to find folder")); - return retval; - } - - /* set the MAIL variable? */ - - if (!(ctrl & PAM_NO_ENV) && est) { - char *tmp; - - tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT)); - if (tmp != NULL) { - sprintf(tmp, MAIL_ENV_FORMAT, folder); - D(("setting env: %s", tmp)); - retval = pam_putenv(pamh, tmp); - _pam_overwrite(tmp); - _pam_drop(tmp); - if (retval != PAM_SUCCESS) { - _pam_overwrite(folder); - _pam_drop(folder); - _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable"); - return retval; - } - } else { - _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable"); - _pam_overwrite(folder); - _pam_drop(folder); - return retval; - } - } else { - D(("not setting " MAIL_ENV_NAME " variable")); - } - - /* - * OK. we've got the mail folder... what about its status? - */ - - if ((est && !(ctrl & PAM_NO_LOGIN)) - || (!est && (ctrl & PAM_LOGOUT_TOO))) { - type = get_mail_status(ctrl, folder); - if (type != NULL) { - retval = report_mail(pamh, ctrl, type, folder); - type = NULL; - } - } - - /* Delete environment variable? */ - if (!est) - (void) pam_putenv(pamh, MAIL_ENV_NAME); - - _pam_overwrite(folder); /* clean up */ - _pam_drop(folder); - - /* indicate success or failure */ - - return retval; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_mail_modstruct = { - "pam_mail", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_mkhomedir/.cvsignore b/modules/pam_mkhomedir/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_mkhomedir/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_mkhomedir/Makefile b/modules/pam_mkhomedir/Makefile deleted file mode 100644 index d518c26f..00000000 --- a/modules/pam_mkhomedir/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_mkhomedir - -include ../Simple.Rules diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c deleted file mode 100644 index 9a4640dd..00000000 --- a/modules/pam_mkhomedir/pam_mkhomedir.c +++ /dev/null @@ -1,377 +0,0 @@ -/* PAM Make Home Dir module - - This module will create a users home directory if it does not exist - when the session begins. This allows users to be present in central - database (such as nis, kerb or ldap) without using a distributed - file system or pre-creating a large number of directories. - - Here is a sample /etc/pam.d/login file for Debian GNU/Linux - 2.1: - - auth requisite pam_securetty.so - auth sufficient pam_ldap.so - auth required pam_pwdb.so - auth optional pam_group.so - auth optional pam_mail.so - account requisite pam_time.so - account sufficient pam_ldap.so - account required pam_pwdb.so - session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 - session required pam_pwdb.so - session optional pam_lastlog.so - password required pam_pwdb.so - - Released under the GNU LGPL version 2 or later - Originally written by Jason Gunthorpe <jgg@debian.org> Feb 1999 - Structure taken from pam_lastlogin by Andrew Morgan - <morgan@parc.power.net> 1996 - */ - -/* I want snprintf dammit */ -#define _GNU_SOURCE 1 -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <pwd.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <dirent.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_SESSION - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* argument parsing */ -#define MKHOMEDIR_DEBUG 020 /* keep quiet about things */ -#define MKHOMEDIR_QUIET 040 /* keep quiet about things */ - -static unsigned int UMask = 0022; -static char SkelDir[BUFSIZ] = "/etc/skel"; /* THIS MODULE IS NOT THREAD SAFE */ - -/* some syslogging */ -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-mkhomedir", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -static int _pam_parse(int flags, int argc, const char **argv) -{ - int ctrl = 0; - - /* does the appliction require quiet? */ - if ((flags & PAM_SILENT) == PAM_SILENT) - ctrl |= MKHOMEDIR_QUIET; - - /* step through arguments */ - for (; argc-- > 0; ++argv) - { - if (!strcmp(*argv, "silent")) { - ctrl |= MKHOMEDIR_QUIET; - } else if (!strncmp(*argv,"umask=",6)) { - UMask = strtol(*argv+6,0,0); - } else if (!strncmp(*argv,"skel=",5)) { - strncpy(SkelDir,*argv+5,sizeof(SkelDir)); - SkelDir[sizeof(SkelDir)-1] = '\0'; - } else { - _log_err(LOG_ERR, "unknown option; %s", *argv); - } - } - - D(("ctrl = %o", ctrl)); - return ctrl; -} - -/* This common function is used to send a message to the applications - conversion function. Our only use is to ask the application to print - an informative message that we are creating a home directory */ -static int converse(pam_handle_t * pamh, int ctrl, int nargs - ,struct pam_message **message - ,struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) - { - - retval = conv->conv(nargs, (const struct pam_message **) message - ,response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && (ctrl & MKHOMEDIR_DEBUG)) - { - _log_err(LOG_DEBUG, "conversation failure [%s]" - ,pam_strerror(pamh, retval)); - } - - } - else - { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - ,pam_strerror(pamh, retval)); - } - - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -/* Ask the application to display a short text string for us. */ -static int make_remark(pam_handle_t * pamh, int ctrl, const char *remark) -{ - int retval; - - if ((ctrl & MKHOMEDIR_QUIET) != MKHOMEDIR_QUIET) - { - struct pam_message msg[1], *mesg[1]; - struct pam_response *resp = NULL; - - mesg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = remark; - - retval = converse(pamh, ctrl, 1, mesg, &resp); - - msg[0].msg = NULL; - if (resp) - { - _pam_drop_reply(resp, 1); - } - } - else - { - D(("keeping quiet")); - retval = PAM_SUCCESS; - } - - D(("returning %s", pam_strerror(pamh, retval))); - return retval; -} - -/* Do the actual work of creating a home dir */ -static int create_homedir(pam_handle_t * pamh, int ctrl, - const struct passwd *pwd, - const char *source, const char *dest) -{ - char remark[BUFSIZ]; - DIR *D; - struct dirent *Dir; - - /* Mention what is happening, if the notification fails that is OK */ - if (snprintf(remark,sizeof(remark),"Creating directory '%s'.", dest) == -1) - return PAM_PERM_DENIED; - - make_remark(pamh, ctrl, remark); - - /* Create the new directory */ - if (mkdir(dest,0700) != 0) - { - _log_err(LOG_DEBUG, "unable to create directory %s",source); - return PAM_PERM_DENIED; - } - if (chmod(dest,0777 & (~UMask)) != 0 || - chown(dest,pwd->pw_uid,pwd->pw_gid) != 0) - { - _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest); - return PAM_PERM_DENIED; - } - - /* See if we need to copy the skel dir over. */ - if ((source == NULL) || (strlen(source) == 0)) - { - return PAM_SUCCESS; - } - - /* Scan the directory */ - D = opendir(source); - if (D == 0) - { - _log_err(LOG_DEBUG, "unable to read directory %s",source); - return PAM_PERM_DENIED; - } - - for (Dir = readdir(D); Dir != 0; Dir = readdir(D)) - { - int SrcFd; - int DestFd; - int Res; - struct stat St; - char newsource[PATH_MAX], newdest[PATH_MAX]; - - /* Skip some files.. */ - if (strcmp(Dir->d_name,".") == 0 || - strcmp(Dir->d_name,"..") == 0) - continue; - - /* Determine what kind of file it is. */ - snprintf(newsource,sizeof(newsource),"%s/%s",source,Dir->d_name); - if (lstat(newsource,&St) != 0) - continue; - - /* We'll need the new file's name. */ - snprintf(newdest,sizeof(newdest),"%s/%s",dest,Dir->d_name); - - /* If it's a directory, recurse. */ - if (S_ISDIR(St.st_mode)) - { - create_homedir(pamh, ctrl, pwd, newsource, newdest); - continue; - } - - /* If it's a symlink, create a new link. */ - if (S_ISLNK(St.st_mode)) - { - char pointed[PATH_MAX]; - memset(pointed, 0, sizeof(pointed)); - if(readlink(newsource, pointed, sizeof(pointed) - 1) != -1) - { - if(symlink(pointed, newdest) == 0) - { - if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0) - { - _log_err(LOG_DEBUG, "unable to chang perms on link %s", - newdest); - return PAM_PERM_DENIED; - } - } - } - continue; - } - - /* If it's not a regular file, it's probably not a good idea to create - * the new device node, FIFO, or whatever it is. */ - if (!S_ISREG(St.st_mode)) - { - continue; - } - - /* Open the source file */ - if ((SrcFd = open(newsource,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) - { - _log_err(LOG_DEBUG, "unable to open src file %s",newsource); - return PAM_PERM_DENIED; - } - stat(newsource,&St); - - /* Open the dest file */ - if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) - { - close(SrcFd); - _log_err(LOG_DEBUG, "unable to open dest file %s",newdest); - return PAM_PERM_DENIED; - } - - /* Set the proper ownership and permissions for the module. We make - the file a+w and then mask it with the set mask. This preseves - execute bits */ - if (fchmod(DestFd,(St.st_mode | 0222) & (~UMask)) != 0 || - fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0) - { - close(SrcFd); - close(DestFd); - _log_err(LOG_DEBUG, "unable to chang perms on copy %s",newdest); - return PAM_PERM_DENIED; - } - - /* Copy the file */ - do - { - Res = read(SrcFd,remark,sizeof(remark)); - if (Res < 0 || write(DestFd,remark,Res) != Res) - { - close(SrcFd); - close(DestFd); - _log_err(LOG_DEBUG, "unable to perform IO"); - return PAM_PERM_DENIED; - } - } - while (Res != 0); - close(SrcFd); - close(DestFd); - } - - return PAM_SUCCESS; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc - ,const char **argv) -{ - int retval, ctrl; - const char *user; - const struct passwd *pwd; - struct stat St; - - /* Parse the flag values */ - ctrl = _pam_parse(flags, argc, argv); - - /* Determine the user name so we can get the home directory */ - retval = pam_get_item(pamh, PAM_USER, (const void **) &user); - if (retval != PAM_SUCCESS || user == NULL || *user == '\0') - { - _log_err(LOG_NOTICE, "user unknown"); - return PAM_USER_UNKNOWN; - } - - /* Get the password entry */ - pwd = getpwnam(user); - if (pwd == NULL) - { - D(("couldn't identify user %s", user)); - return PAM_CRED_INSUFFICIENT; - } - - /* Stat the home directory, if something exists then we assume it is - correct and return a success*/ - if (stat(pwd->pw_dir,&St) == 0) - return PAM_SUCCESS; - - return create_homedir(pamh,ctrl,pwd,SkelDir,pwd->pw_dir); -} - -/* Ignore */ -PAM_EXTERN -int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -/* static module data */ -struct pam_module _pam_mkhomedir_modstruct = -{ - "pam_mkhomedir", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; - -#endif diff --git a/modules/pam_motd/.cvsignore b/modules/pam_motd/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_motd/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_motd/Makefile b/modules/pam_motd/Makefile deleted file mode 100644 index ae4acb8c..00000000 --- a/modules/pam_motd/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_motd - -include ../Simple.Rules diff --git a/modules/pam_motd/pam_motd.c b/modules/pam_motd/pam_motd.c deleted file mode 100644 index 759cc017..00000000 --- a/modules/pam_motd/pam_motd.c +++ /dev/null @@ -1,123 +0,0 @@ -/* pam_motd module */ - -/* - * Modified for pam_motd by Ben Collins <bcollins@debian.org> - * - * Based off of: - * $Id$ - * - * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 - * - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pwd.h> - -#include <security/_pam_macros.h> -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_SESSION -#define DEFAULT_MOTD "/etc/motd" - -#include <security/pam_modules.h> - -/* --- session management functions (only) --- */ - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - return PAM_IGNORE; -} - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - int retval = PAM_IGNORE; - int fd; - char *mtmp=NULL; - const char *motd_path=NULL; - struct pam_conv *conversation; - struct pam_message message; - struct pam_message *pmessage = &message; - struct pam_response *resp = NULL; - struct stat st; - - if (flags & PAM_SILENT) { - return retval; - } - - for (; argc-- > 0; ++argv) { - if (!strncmp(*argv,"motd=",5)) { - - motd_path = (char *) strdup(5+*argv); - if (motd_path != NULL) { - D(("set motd path: %s (and a memory leak)", motd_path)); - } else { - D(("failed to duplicate motd path - ignored")); - } - } - } - - if (motd_path == NULL) - motd_path = DEFAULT_MOTD; - - message.msg_style = PAM_TEXT_INFO; - - if ((fd = open(motd_path, O_RDONLY, 0)) >= 0) { - /* fill in message buffer with contents of motd */ - if ((fstat(fd, &st) < 0) || !st.st_size) - return retval; - message.msg = mtmp = malloc(st.st_size+1); - /* if malloc failed... */ - if (!message.msg) return retval; - read(fd, mtmp, st.st_size); - if (mtmp[st.st_size-1] == '\n') - mtmp[st.st_size-1] = '\0'; - else - mtmp[st.st_size] = '\0'; - close(fd); - /* Use conversation function to give user contents of motd */ - pam_get_item(pamh, PAM_CONV, (const void **)&conversation); - conversation->conv(1, (const struct pam_message **)&pmessage, - &resp, conversation->appdata_ptr); - free(mtmp); - if (resp) - _pam_drop_reply(resp, 1); - } - - return retval; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_motd_modstruct = { - "pam_motd", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_nologin/.cvsignore b/modules/pam_nologin/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_nologin/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_nologin/Makefile b/modules/pam_nologin/Makefile deleted file mode 100644 index 130787e7..00000000 --- a/modules/pam_nologin/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_nologin - -include ../Simple.Rules diff --git a/modules/pam_nologin/README b/modules/pam_nologin/README deleted file mode 100644 index 11dc7635..00000000 --- a/modules/pam_nologin/README +++ /dev/null @@ -1,23 +0,0 @@ -# $Id$ -# - -This module always lets root in; it lets other users in only if the file -/etc/nologin doesn't exist. In any case, if /etc/nologin exists, it's -contents are displayed to the user. - -The default return value for this module is PAM_IGNORE, you can -override this with the successok module argument. - -module services provided: - - auth _authenticate and _setcred - account _acct_mgmt - -optional arguments: - - file=<alternative-nologin-pathname> - choose a different file - successok - return PAM_SUCCESS if no file - -[Original README by Michael K. Johnson] - - diff --git a/modules/pam_nologin/pam_nologin.c b/modules/pam_nologin/pam_nologin.c deleted file mode 100644 index 7b2394af..00000000 --- a/modules/pam_nologin/pam_nologin.c +++ /dev/null @@ -1,197 +0,0 @@ -/* pam_nologin module */ - -/* - * $Id$ - * - * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pwd.h> - -#include <security/_pam_macros.h> -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -#include <security/_pam_modutil.h> - -/* - * parse some command line options - */ -struct opt_s { - int retval_when_nofile; - const char *nologin_file; -}; - -static void parse_args(pam_handle_t *pamh, int argc, const char **argv, - struct opt_s *opts) -{ - int i; - - memset(opts, 0, sizeof(*opts)); - - opts->retval_when_nofile = PAM_IGNORE; - opts->nologin_file = "/etc/nologin"; - - for (i=0; i<argc; ++i) { - if (!strcmp("successok", argv[i])) { - opts->retval_when_nofile = PAM_SUCCESS; - } else if (!memcmp("file=", argv[i], 5)) { - opts->nologin_file = argv[i] + 5; - } else { - /* XXX - ignore for now. Later, we'll use the logging - function in pammodutils */ - } - } -} - -/* - * do the meat of the work for this module - */ - -static int perform_check(pam_handle_t *pamh, struct opt_s *opts) -{ - const char *username; - int retval = PAM_SUCCESS; - int fd; - - retval = opts->retval_when_nofile; - - if ((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username) { - return PAM_USER_UNKNOWN; - } - - if ((fd = open(opts->nologin_file, O_RDONLY, 0)) >= 0) { - - char *mtmp=NULL; - struct passwd *user_pwd; - struct pam_conv *conversation; - struct pam_message message; - struct pam_message *pmessage = &message; - struct pam_response *resp = NULL; - struct stat st; - - user_pwd = _pammodutil_getpwnam(pamh, username); - if (user_pwd == NULL) { - - retval = PAM_USER_UNKNOWN; - message.msg_style = PAM_ERROR_MSG; - - } else if (user_pwd->pw_uid) { - - retval = PAM_AUTH_ERR; - message.msg_style = PAM_ERROR_MSG; - - } else { - - /* root can still log in; lusers cannot */ - message.msg_style = PAM_TEXT_INFO; - - } - - /* fill in message buffer with contents of /etc/nologin */ - if (fstat(fd, &st) < 0) { - /* give up trying to display message */ - goto clean_up_fd; - } - - message.msg = mtmp = malloc(st.st_size+1); - if (!message.msg) { - /* if malloc failed... */ - retval = PAM_BUF_ERR; - goto clean_up_fd; - } - - read(fd, mtmp, st.st_size); - mtmp[st.st_size] = '\000'; - - /* - * Use conversation function to give user contents of /etc/nologin - */ - - pam_get_item(pamh, PAM_CONV, (const void **)&conversation); - (void) conversation->conv(1, (const struct pam_message **)&pmessage, - &resp, conversation->appdata_ptr); - free(mtmp); - - if (resp) { - _pam_drop_reply(resp, 1); - } - - clean_up_fd: - - close(fd); - } - - return retval; -} - -/* --- authentication management functions --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - struct opt_s opts; - - parse_args(pamh, argc, argv, &opts); - - return perform_check(pamh, &opts); -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - struct opt_s opts; - - parse_args(pamh, argc, argv, &opts); - - return opts.retval_when_nofile; -} - -/* --- account management function --- */ - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - struct opt_s opts; - - parse_args(pamh, argc, argv, &opts); - - return perform_check(pamh, &opts); -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_nologin_modstruct = { - "pam_nologin", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_permit/.cvsignore b/modules/pam_permit/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_permit/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_permit/Makefile b/modules/pam_permit/Makefile deleted file mode 100644 index b4cc3b5b..00000000 --- a/modules/pam_permit/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_permit - -include ../Simple.Rules diff --git a/modules/pam_permit/README b/modules/pam_permit/README deleted file mode 100644 index c399710c..00000000 --- a/modules/pam_permit/README +++ /dev/null @@ -1,4 +0,0 @@ -# $Id$ -# - -this module always returns PAM_SUCCESS, it ignores all options. diff --git a/modules/pam_permit/pam_permit.c b/modules/pam_permit/pam_permit.c deleted file mode 100644 index ea23b312..00000000 --- a/modules/pam_permit/pam_permit.c +++ /dev/null @@ -1,112 +0,0 @@ -/* pam_permit module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 - * - */ - -#define DEFAULT_USER "nobody" - -#include <stdio.h> - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -/* --- authentication management functions --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int retval; - const char *user=NULL; - - /* - * authentication requires we know who the user wants to be - */ - retval = pam_get_user(pamh, &user, NULL); - if (retval != PAM_SUCCESS) { - D(("get user returned error: %s", pam_strerror(pamh,retval))); - return retval; - } - if (user == NULL || *user == '\0') { - D(("username not known")); - pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); - } - user = NULL; /* clean up */ - - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -/* --- account management functions --- */ - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -/* --- password management --- */ - -PAM_EXTERN -int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -/* --- session management --- */ - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - -/* end of module definition */ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_permit_modstruct = { - "pam_permit", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok -}; - -#endif diff --git a/modules/pam_pwdb/.cvsignore b/modules/pam_pwdb/.cvsignore deleted file mode 100644 index f0420bac..00000000 --- a/modules/pam_pwdb/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -dynamic -pwdb_chkpwd diff --git a/modules/pam_pwdb/BUGS b/modules/pam_pwdb/BUGS deleted file mode 100644 index a3608a7c..00000000 --- a/modules/pam_pwdb/BUGS +++ /dev/null @@ -1,3 +0,0 @@ -$Id$ - -As of Linux-PAM-0.52 this is new. No known bugs yet. diff --git a/modules/pam_pwdb/CHANGELOG b/modules/pam_pwdb/CHANGELOG deleted file mode 100644 index 7bad5cd8..00000000 --- a/modules/pam_pwdb/CHANGELOG +++ /dev/null @@ -1,10 +0,0 @@ -$Id$ - -Tue Apr 23 12:28:09 EDT 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu) - - * PAM_DISALLOW_NULL_AUTHTOK implemented in the authentication module - * pam_sm_open_session() and pam_sm_close_session() implemented - A new "trace" flag added to flags of /etc/pam.conf. Using this - flag system administrator is able to make pam_unix module provide - very extensive audit trail sent so syslog with LOG_AUTHPRIV level. - * pam_sm_set_cred() is done diff --git a/modules/pam_pwdb/Makefile b/modules/pam_pwdb/Makefile deleted file mode 100644 index 2b581dcd..00000000 --- a/modules/pam_pwdb/Makefile +++ /dev/null @@ -1,124 +0,0 @@ -# $Id$ -# -# This Makefile controls a build process of the pam_unix module -# for Linux-PAM. You should not modify this Makefile. -# -# rewritten to compile new module Andrew Morgan -# <morgan@parc.power.net> 1996/11/6 -# - -include ../../Make.Rules - -ifeq ($(HAVE_LIBPWDB),yes) - -EXTRALS += -lpwdb -EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" - -ifeq ($(HAVE_LIBCRYPT),yes) - EXTRALS += -lcrypt -endif - -TITLE=pam_pwdb -CHKPWD=pwdb_chkpwd - -LIBSRC = $(TITLE).c -LIBOBJ = $(TITLE).o -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -#LIBOBJS = $(addprefix static/,$(LIBOBJ)) -LIBDEPS = pam_unix_acct.-c pam_unix_auth.-c pam_unix_passwd.-c \ - pam_unix_sess.-c pam_unix_pwupd.-c support.-c bigcrypt.-c - -PLUS += md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o -CFLAGS += $(EXTRAS) - -ifdef DYNAMIC -LIBSHARED = $(TITLE).so -endif -#ifdef STATIC -#LIBSTATIC = lib$(TITLE).o -#endif - -all: info dirs $(PLUS) $(LIBSHARED) $(LIBSTATIC) register $(CHKPWD) - -dynamic/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS) - $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -#static/$(LIBOBJ) : $(LIBSRC) $(LIBDEPS) -# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -info: - @echo - @echo "*** Building PAM_pwdb module..." - @echo - -$(CHKPWD): pwdb_chkpwd.o md5_good.o md5_broken.o \ - md5_crypt_good.o md5_crypt_broken.o - $(CC) -o $(CHKPWD) $^ -lpwdb - -pwdb_chkpwd.o: pwdb_chkpwd.c pam_unix_md.-c bigcrypt.-c - -md5_good.o: md5.c - $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_broken.o: md5.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_crypt_good.o: md5_crypt.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_crypt_broken.o: md5_crypt.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ - $(TARGET_ARCH) -c $< -o $@ - -dirs: -ifdef DYNAMIC - @$(MKDIR) ./dynamic -endif -#ifdef STATIC -# @$(MKDIR) ./static -#endif - -register: -#ifdef STATIC -# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) -#endif - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) - -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(EXTRALS) -endif - -#ifdef STATIC -#$(LIBOBJS): $(LIBSRC) -# -#$(LIBSTATIC): $(LIBOBJS) -# $(LD) -r -o $@ $(LIBOBJS) $(PLUS) $(EXTRALS) -#endif - -install: all - $(MKDIR) $(FAKEROOT)$(SECUREDIR) -ifdef DYNAMIC - $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) -endif - $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) - $(INSTALL) -m 4555 $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED) - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so - rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) - -clean: - rm -f $(CHKPWD) $(LIBOBJD) $(LIBOBJS) $(MOREDELS) core *~ *.o *.so - rm -f *.a *.o *.so *.bak - rm -fr dynamic static - -else - -include ../dont_makefile - -endif diff --git a/modules/pam_pwdb/README b/modules/pam_pwdb/README deleted file mode 100644 index 4f420855..00000000 --- a/modules/pam_pwdb/README +++ /dev/null @@ -1,41 +0,0 @@ -This is the pam_unix module. It has been significantly rewritten since -.51 was released (due mostly to the efforts of Cristian Gafton), and -now takes more options and correctly updates vanilla UNIX/shadow/md5 -passwords. - -[Please read the source and make a note of all the warnings there, as -the license suggests -- use at your own risk.] - -So far as I am concerned this module is now pretty stable. If you find -any bugs, PLEASE tell me! <morgan@linux.kernel.org> - -Options recognized by this module are as follows: - - debug - log more debugging info - audit - a little more extreme than debug - use_first_pass - don't prompt the user for passwords - take them from PAM_ items instead - try_first_pass - don't prompt the user for the passwords - unless PAM_(OLD)AUTHTOK is unset - use_authtok - like try_first_pass, but *fail* if the new - PAM_AUTHTOK has not been previously set. - (intended for stacking password modules only) - not_set_pass - don't set the PAM_ items with the passwords - used by this module. - shadow - try to maintian a shadow based system. - unix - when changing passwords, they are placed - in the /etc/passwd file - md5 - when a user changes their password next, - encrypt it with the md5 algorithm. - bigcrypt - when a user changes their password next, - excrypt it with the DEC C2-algorithm(0). - nodelay - used to prevent failed authentication - resulting in a delay of about 1 second. - -There is some support for building a shadow file on-the-fly from an -/etc/passwd file. This is VERY alpha. If you want to play with it you -should read the source to find the appropriate #define that you will -need. - ---------------------- -Andrew Morgan <morgan@linux.kernel.org> diff --git a/modules/pam_pwdb/TODO b/modules/pam_pwdb/TODO deleted file mode 100644 index 9dc7fc7e..00000000 --- a/modules/pam_pwdb/TODO +++ /dev/null @@ -1,34 +0,0 @@ -$Id$ - - * get NIS working - * .. including "nonis" argument - * add helper binary - -Wed Sep 4 23:40:09 PDT 1996 Andrew G. Morgan - - * verify that it works for everyone - * look more seriously at the issue of generating a shadow - system on the fly - * add some more password flavors - -Thu Aug 29 06:26:42 PDT 1996 Andrew G. Morgan - - * check that complete rewrite works! ;^) - * complete shadow support to the password changing code. - Also some code needed here for session managment? - (both pam.conf argument to turn it on/off, and some - conditional compilation.) - * md5 passwords... - * make the exclusive nature of the arguments work. That is, - only recognize the flags when appropriate. - -Wed May 8 19:08:49 EDT 1996 Alexander O. Yuriev - - * support.c should go. - -Tue Apr 23 21:43:55 EDT 1996 Alexander O. Yuriev - - * pam_sm_chauth_tok() should be written - * QUICK FIX: pam_sm_setcred() probably returns incorrect error code - - diff --git a/modules/pam_pwdb/bigcrypt.-c b/modules/pam_pwdb/bigcrypt.-c deleted file mode 100644 index 321f2491..00000000 --- a/modules/pam_pwdb/bigcrypt.-c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This function implements the "bigcrypt" algorithm specifically for - * Linux-PAM. - * - * This algorithm is algorithm 0 (default) shipped with the C2 secure - * implementation of Digital UNIX. - * - * Disclaimer: This work is not based on the source code to Digital - * UNIX, nor am I connected to Digital Equipment Corp, in any way - * other than as a customer. This code is based on published - * interfaces and reasonable guesswork. - * - * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8 - * characters or less. Each block is encrypted using the standard UNIX - * libc crypt function. The result of the encryption for one block - * provides the salt for the suceeding block. - * - * Restrictions: The buffer used to hold the encrypted result is - * statically allocated. (see MAX_PASS_LEN below). This is necessary, - * as the returned pointer points to "static data that are overwritten - * by each call", (XPG3: XSI System Interface + Headers pg 109), and - * this is a drop in replacement for crypt(); - * - * Andy Phillips <atp@mssl.ucl.ac.uk> - */ - -/* - * Max cleartext password length in segments of 8 characters this - * function can deal with (16 segments of 8 chars= max 128 character - * password). - */ - -#define MAX_PASS_LEN 16 -#define SEGMENT_SIZE 8 -#define SALT_SIZE 2 -#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE) -#define ESEGMENT_SIZE 11 -#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1) - -static char *bigcrypt(const char *key, const char *salt) -{ - static char dec_c2_cryptbuf[CBUF_SIZE]; /* static storage area */ - - unsigned long int keylen,n_seg,j; - char *cipher_ptr,*plaintext_ptr,*tmp_ptr,*salt_ptr; - char keybuf[KEYBUF_SIZE+1]; - - D(("called with key='%s', salt='%s'.", key, salt)); - - /* reset arrays */ - memset(keybuf, 0, KEYBUF_SIZE+1); - memset(dec_c2_cryptbuf, 0, CBUF_SIZE); - - /* fill KEYBUF_SIZE with key */ - strncpy(keybuf, key, KEYBUF_SIZE); - - /* deal with case that we are doing a password check for a - conventially encrypted password: the salt will be - SALT_SIZE+ESEGMENT_SIZE long. */ - if (strlen(salt) == (SALT_SIZE+ESEGMENT_SIZE)) - keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */ - - keylen = strlen(keybuf); - - if (!keylen) { - n_seg = 1; - } else { - /* work out how many segments */ - n_seg = 1 + ((keylen-1)/SEGMENT_SIZE); - } - - if (n_seg > MAX_PASS_LEN) - n_seg = MAX_PASS_LEN; /* truncate at max length */ - - /* set up some pointers */ - cipher_ptr = dec_c2_cryptbuf; - plaintext_ptr = keybuf; - - /* do the first block with supplied salt */ - tmp_ptr = crypt(plaintext_ptr,salt); /* libc crypt() */ - - /* and place in the static area */ - strncpy(cipher_ptr, tmp_ptr, 13); - cipher_ptr += ESEGMENT_SIZE + SALT_SIZE; - plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */ - - /* change the salt (1st 2 chars of previous block) - this was found - by dowsing */ - - salt_ptr = cipher_ptr - ESEGMENT_SIZE; - - /* so far this is identical to "return crypt(key, salt);", if - there is more than one block encrypt them... */ - - if (n_seg > 1) { - for (j=2; j <= n_seg; j++) { - - tmp_ptr = crypt(plaintext_ptr, salt_ptr); - - /* skip the salt for seg!=0 */ - strncpy(cipher_ptr, (tmp_ptr+SALT_SIZE), ESEGMENT_SIZE); - - cipher_ptr += ESEGMENT_SIZE; - plaintext_ptr += SEGMENT_SIZE; - salt_ptr = cipher_ptr - ESEGMENT_SIZE; - } - } - - D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf)); - - /* this is the <NUL> terminated encrypted password */ - - return dec_c2_cryptbuf; -} diff --git a/modules/pam_pwdb/md5.c b/modules/pam_pwdb/md5.c deleted file mode 100644 index 335908df..00000000 --- a/modules/pam_pwdb/md5.c +++ /dev/null @@ -1,255 +0,0 @@ -/* $Id$ - * - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - */ - -#include <string.h> -#include "md5.h" - -#ifndef HIGHFIRST -#define byteReverse(buf, len) /* Nothing */ -#else -static void byteReverse(unsigned char *buf, unsigned longs); - -#ifndef ASM_MD5 -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - uint32 t; - do { - t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Name(MD5Init)(struct MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301U; - ctx->buf[1] = 0xefcdab89U; - ctx->buf[2] = 0x98badcfeU; - ctx->buf[3] = 0x10325476U; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len) -{ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; - - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -#ifndef ASM_MD5 - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16]) -{ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#endif diff --git a/modules/pam_pwdb/md5.h b/modules/pam_pwdb/md5.h deleted file mode 100644 index 75c4dbac..00000000 --- a/modules/pam_pwdb/md5.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MD5_H -#define MD5_H - -typedef unsigned int uint32; - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -void GoodMD5Init(struct MD5Context *); -void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned); -void GoodMD5Final(unsigned char digest[16], struct MD5Context *); -void GoodMD5Transform(uint32 buf[4], uint32 const in[16]); -void BrokenMD5Init(struct MD5Context *); -void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned); -void BrokenMD5Final(unsigned char digest[16], struct MD5Context *); -void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]); - -char *Goodcrypt_md5(const char *pw, const char *salt); -char *Brokencrypt_md5(const char *pw, const char *salt); - -/* -* This is needed to make RSAREF happy on some MS-DOS compilers. -*/ - -typedef struct MD5Context MD5_CTX; - -#endif /* MD5_H */ diff --git a/modules/pam_pwdb/md5_crypt.c b/modules/pam_pwdb/md5_crypt.c deleted file mode 100644 index 4226dd1e..00000000 --- a/modules/pam_pwdb/md5_crypt.c +++ /dev/null @@ -1,138 +0,0 @@ -/* $Id$ - * - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * - * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp - * - */ - -#include <string.h> -#include "md5.h" - -static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void -to64(char *s, unsigned long v, int n) -{ - while (--n >= 0) { - *s++ = itoa64[v&0x3f]; - v >>= 6; - } -} - -/* - * UNIX password - * - * Use MD5 for what it is best at... - */ - -char * MD5Name(crypt_md5)(const char *pw, const char *salt) -{ - const char *magic = "$1$"; - /* This string is magic for this algorithm. Having - * it this way, we can get get better later on */ - static char passwd[120], *p; - static const char *sp,*ep; - unsigned char final[16]; - int sl,pl,i,j; - MD5_CTX ctx,ctx1; - unsigned long l; - - /* Refine the Salt first */ - sp = salt; - - /* If it starts with the magic string, then skip that */ - if(!strncmp(sp,magic,strlen(magic))) - sp += strlen(magic); - - /* It stops at the first '$', max 8 chars */ - for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) - continue; - - /* get the length of the true salt */ - sl = ep - sp; - - MD5Name(MD5Init)(&ctx); - - /* The password first, since that is what is most unknown */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw)); - - /* Then our magic string */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic)); - - /* Then the raw salt */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl); - - /* Then just as many characters of the MD5(pw,salt,pw) */ - MD5Name(MD5Init)(&ctx1); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Final)(final,&ctx1); - for(pl = strlen(pw); pl > 0; pl -= 16) - MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); - - /* Don't leave anything around in vm they could use. */ - memset(final,0,sizeof final); - - /* Then something really weird... */ - for (j=0,i = strlen(pw); i ; i >>= 1) - if(i&1) - MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1); - else - MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1); - - /* Now make the output string */ - strcpy(passwd,magic); - strncat(passwd,sp,sl); - strcat(passwd,"$"); - - MD5Name(MD5Final)(final,&ctx); - - /* - * and now, just to make sure things don't run too fast - * On a 60 Mhz Pentium this takes 34 msec, so you would - * need 30 seconds to build a 1000 entry dictionary... - */ - for(i=0;i<1000;i++) { - MD5Name(MD5Init)(&ctx1); - if(i & 1) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - else - MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); - - if(i % 3) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); - - if(i % 7) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - - if(i & 1) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); - else - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Final)(final,&ctx1); - } - - p = passwd + strlen(passwd); - - l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; - l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; - l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; - l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; - l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; - l = final[11] ; to64(p,l,2); p += 2; - *p = '\0'; - - /* Don't leave anything around in vm they could use. */ - memset(final,0,sizeof final); - - return passwd; -} - diff --git a/modules/pam_pwdb/pam_pwdb.c b/modules/pam_pwdb/pam_pwdb.c deleted file mode 100644 index d736c6a8..00000000 --- a/modules/pam_pwdb/pam_pwdb.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * $Id$ - * - * This is the single file that will be compiled for pam_unix. - * it includes each of the modules that have beed defined in the .-c - * files in this directory. - * - * It is a little ugly to do it this way, but it is a simple way of - * defining static functions only once, and yet keeping the separate - * files modular. If you can think of something better, please email - * Andrew Morgan <morgan@linux.kernel.org> - * - * See the end of this file for Copyright information. - */ - -static const char rcsid[] = -"$Id$\n" -" - PWDB Pluggable Authentication module. <morgan@linux.kernel.org>" -; - -/* #define DEBUG */ - -#include <security/_pam_aconf.h> - -#include <sys/types.h> -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <syslog.h> -#include <time.h> /* for time() */ -#include <fcntl.h> -#include <ctype.h> - -#include <sys/time.h> -#include <unistd.h> - -#include <pwdb/pwdb_public.h> - -/* indicate the following groups are defined */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include "./support.-c" - -/* - * PAM framework looks for these entry-points to pass control to the - * authentication module. - */ - -#include "./pam_unix_auth.-c" - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_auth( pamh, ctrl ); - pwdb_end(); - - if ( on(UNIX_LIKE_AUTH, ctrl) ) { - D(("recording return code for next time [%d]", retval)); - pam_set_data(pamh, "pwdb_setcred_return", (void *) retval, NULL); - } - - D(("done. [%s]", pam_strerror(pamh, retval))); - - return retval; -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags - , int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_set_credentials(pamh, ctrl); - pwdb_end(); - - if ( on(UNIX_LIKE_AUTH, ctrl) ) { - int *pretval = &retval; - - D(("recovering return code from auth call")); - pam_get_data(pamh, "pwdb_setcred_return", (const void **) pretval); - D(("recovered data indicates that old retval was %d", retval)); - } - - return retval; -} - -/* - * PAM framework looks for these entry-points to pass control to the - * account management module. - */ - -#include "./pam_unix_acct.-c" - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_acct_mgmt(pamh, ctrl); - pwdb_end(); - - D(("done.")); - - return retval; -} - -/* - * PAM framework looks for these entry-points to pass control to the - * session module. - */ - -#include "./pam_unix_sess.-c" - -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_open_session(pamh, ctrl); - pwdb_end(); - - return retval; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_close_session(pamh, ctrl); - pwdb_end(); - - return retval; -} - -/* - * PAM framework looks for these entry-points to pass control to the - * password changing module. - */ - -#include "./pam_unix_passwd.-c" - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - D(("called.")); - - pwdb_start(); - ctrl = set_ctrl(flags, argc, argv); - retval = _unix_chauthtok(pamh, ctrl); - pwdb_end(); - - D(("done.")); - - return retval; -} - -/* static module data */ - -#ifdef PAM_STATIC -struct pam_module _pam_pwdb_modstruct = { - "pam_pwdb", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok -}; - -#endif - -/* - * Copyright (c) Andrew G. Morgan, 1996. All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/pam_unix_acct.-c b/modules/pam_pwdb/pam_unix_acct.-c deleted file mode 100644 index 0ee3b3d5..00000000 --- a/modules/pam_pwdb/pam_unix_acct.-c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * $Id$ - * - * See end of file for copyright information - */ - -static const char rcsid_acct[] = -"$Id$\n" -" - PAM_PWDB account management <gafton@redhat.com>"; - -/* the shadow suite has accout managment.. */ - -static int _shadow_acct_mgmt_exp(pam_handle_t *pamh, unsigned int ctrl, - const struct pwdb *pw, const char *uname) -{ - const struct pwdb_entry *pwe = NULL; - time_t curdays; - int last_change, max_change; - int retval; - - D(("called.")); - - /* Now start the checks */ - - curdays = time(NULL)/(60*60*24); /* today */ - - /* First: has account expired ? (CG) - * - expire < curdays - * - or (last_change + max_change + defer_change) < curdays - * - in both cases, deny access - */ - - D(("pwdb_get_entry")); - retval = pwdb_get_entry(pw, "expire", &pwe); - if (retval == PWDB_SUCCESS) { - int expire; - - expire = *( (const int *) pwe->value ); - (void) pwdb_entry_delete(&pwe); /* no longer needed */ - - if ((curdays > expire) && (expire > 0)) { - - _log_err(LOG_NOTICE - , "acct: account %s has expired (account expired)" - , uname); - make_remark(pamh, ctrl, PAM_ERROR_MSG - , "Your account has expired; " - "please contact your system administrator"); - - D(("account expired")); - return PAM_ACCT_EXPIRED; - } - } - - D(("pwdb_get_entry")); - retval = pwdb_get_entry(pw, "last_change", &pwe); - if ( retval == PWDB_SUCCESS ) { - last_change = *( (const int *) pwe->value ); - } else { - last_change = curdays; - } - (void) pwdb_entry_delete(&pwe); - - D(("pwdb_get_entry")); - retval = pwdb_get_entry(pw, "max_change", &pwe); - if ( retval == PWDB_SUCCESS ) { - max_change = *( (const int *) pwe->value ); - } else { - max_change = -1; - } - (void) pwdb_entry_delete(&pwe); - - D(("pwdb_get_entry")); - retval = pwdb_get_entry(pw, "defer_change", &pwe); - if (retval == PWDB_SUCCESS) { - int defer_change; - - defer_change = *( (const int *) pwe->value ); - (void) pwdb_entry_delete(&pwe); - - if ((curdays > (last_change + max_change + defer_change)) - && (max_change != -1) && (defer_change != -1) - && (last_change > 0)) { - - if ( on(UNIX_DEBUG, ctrl) ) { - _log_err(LOG_NOTICE, "acct: account %s has expired " - "(failed to change password)", uname); - } - make_remark(pamh, ctrl, PAM_ERROR_MSG - , "Your password has expired; " - "please see your system administrator"); - - D(("account expired2")); - return PAM_ACCT_EXPIRED; - } - } - - /* Now test if the password is expired, but the user still can - * change their password. (CG) - * - last_change = 0 - * - last_change + max_change < curdays - */ - - D(("when was the last change")); - if (last_change == 0) { - - if ( on(UNIX_DEBUG, ctrl) ) { - _log_err(LOG_NOTICE - , "acct: expired password for user %s (root enforced)" - , uname); - } - make_remark(pamh, ctrl, PAM_ERROR_MSG - , "You are required to change your password immediately" - ); - - D(("need a new password")); - return PAM_NEW_AUTHTOK_REQD; - } - - if (((last_change + max_change) < curdays) && - (max_change < 99999) && (max_change > 0)) { - - if ( on(UNIX_DEBUG, ctrl) ) { - _log_err(LOG_DEBUG - , "acct: expired password for user %s (password aged)" - , uname); - } - make_remark(pamh, ctrl, PAM_ERROR_MSG - , "Your password has expired; please change it!"); - - D(("need a new password 2")); - return PAM_NEW_AUTHTOK_REQD; - } - - /* - * Now test if the password is about to expire (CG) - * - last_change + max_change - curdays <= warn_change - */ - - retval = pwdb_get_entry(pw, "warn_change", &pwe); - if ( retval == PWDB_SUCCESS ) { - int warn_days, daysleft; - - daysleft = last_change + max_change - curdays; - warn_days = *((const int *) pwe->value); - (void) pwdb_entry_delete(&pwe); - - if ((daysleft <= warn_days) && (warn_days > 0)) { - char *s; - - if ( on(UNIX_DEBUG, ctrl) ) { - _log_err(LOG_DEBUG - , "acct: password for user %s will expire in %d days" - , uname, daysleft); - } - -#define LocalComment "Warning: your password will expire in %d day%s" - if ((s = (char *) malloc(30+sizeof(LocalComment))) == NULL) { - _log_err(LOG_CRIT, "malloc failure in " __FILE__); - retval = PAM_BUF_ERR; - } else { - - sprintf(s, LocalComment, daysleft, daysleft == 1 ? "":"s"); - - make_remark(pamh, ctrl, PAM_TEXT_INFO, s); - free(s); - } -#undef LocalComment - } - } else { - retval = PAM_SUCCESS; - } - - D(("all done")); - return retval; -} - - -/* - * this function checks for the account details. The user may not be - * permitted to log in at this time etc.. Within the context of - * vanilla Unix, this function simply does nothing. The shadow suite - * added password/account expiry, but PWDB takes care of this - * transparently. - */ - -static int _unix_acct_mgmt(pam_handle_t *pamh, unsigned int ctrl) -{ - const struct pwdb *pw = NULL; - - char *uname=NULL; - int retval; - - D(("called.")); - - /* identify user */ - - retval = pam_get_item(pamh,PAM_USER,(const void **)&uname); - D(("user = `%s'", uname)); - if (retval != PAM_SUCCESS || uname == NULL) { - _log_err(LOG_ALERT - , "acct; could not identify user (from uid=%d)" - , getuid()); - return PAM_USER_UNKNOWN; - } - - /* get database information for user */ - - retval = pwdb_locate("user", PWDB_DEFAULT, uname, PWDB_ID_UNKNOWN, &pw); - if (retval != PWDB_SUCCESS || pw == NULL) { - - _log_err(LOG_ALERT, "acct; %s (%s from uid=%d)" - , pwdb_strerror(retval), uname, getuid()); - if ( pw ) { - (void) pwdb_delete(&pw); - } - return PAM_USER_UNKNOWN; - } - - /* now check the user's times etc.. */ - - retval = _shadow_acct_mgmt_exp(pamh, ctrl, pw, uname); - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, "expiry check failed for '%s'", uname); - } - - /* Done with pw */ - - (void) pwdb_delete(&pw); - - /* all done */ - - D(("done.")); - return retval; -} - -/* - * Copyright (c) Elliot Lee, 1996. - * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996. - * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/pam_unix_auth.-c b/modules/pam_pwdb/pam_unix_auth.-c deleted file mode 100644 index e4dfe136..00000000 --- a/modules/pam_pwdb/pam_unix_auth.-c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * $Id$ - * - * See end of file for Copyright information. - */ - -static const char rcsid_auth[] = -"$Id$: pam_unix_auth.-c,v 1.2 1996/09/05 06:46:53 morgan Exp morgan $\n" -" - PAM_PWDB authentication functions. <morgan@parc.power.net>"; - -/* - * _unix_auth() is a front-end for UNIX/shadow authentication - * - * First, obtain the password from the user. Then use a - * routine in 'support.-c' to authenticate the user. - */ - -#define _UNIX_AUTHTOK "-UN*X-PASS" - -static int _unix_auth(pam_handle_t *pamh, unsigned int ctrl) -{ - int retval; - const char *name, *p; - - D(("called.")); - - /* get the user'name' */ - - retval = _unix_get_user(pamh, ctrl, NULL, &name); - if (retval != PAM_SUCCESS ) { - if (retval != PAM_CONV_AGAIN) { - if ( on(UNIX_DEBUG,ctrl) ) { - _log_err(LOG_DEBUG, "auth could not identify user"); - } - } else { - D(("pam_get_user/conv() function is not ready yet")); - /* it is safe to resume this function so we translate this - retval to the value that indicates we're happy to resume. */ - retval = PAM_INCOMPLETE; - } - return retval; - } - - /* if this user does not have a password... */ - - if ( _unix_blankpasswd(ctrl, name) ) { - D(("user '%s' has blank passwd", name)); - name = NULL; - return PAM_SUCCESS; - } - - /* get this user's authentication token */ - - retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL - , _UNIX_AUTHTOK, &p); - if (retval != PAM_SUCCESS) { - if (retval != PAM_CONV_AGAIN) { - _log_err(LOG_CRIT, "auth could not identify password for [%s]" - , name); - } else { - D(("conversation function is not ready yet")); - /* it is safe to resume this function so we translate this - retval to the value that indicates we're happy to resume. */ - retval = PAM_INCOMPLETE; - } - name = NULL; - return retval; - } - D(("user=%s, password=[%s]", name, p)); - - /* verify the password of this user */ - retval = _unix_verify_password(pamh, name, p, ctrl); - name = p = NULL; - - D(("done [%d]", retval)); - - return retval; -} - -/* - * This function is for setting unix credentials. Sun has indicated - * that there are *NO* authentication credentials for unix. The - * obvious credentials would be the group membership of the user as - * listed in the /etc/group file. However, Sun indicates that it is - * the responsibility of the application to set these. - */ - -static int _unix_set_credentials(pam_handle_t *pamh, unsigned int ctrl) -{ - D(("called <empty function> returning.")); - - return PAM_SUCCESS; -} - -/******************************************************************** - * Copyright (c) Alexander O. Yuriev, 1996. - * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996 - * Copyright (c) Cristian Gafton <gafton@redhat.com> 1996, 1997 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - diff --git a/modules/pam_pwdb/pam_unix_md.-c b/modules/pam_pwdb/pam_unix_md.-c deleted file mode 100644 index 65476732..00000000 --- a/modules/pam_pwdb/pam_unix_md.-c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This function is a front-end for the message digest algorithms used - * to compute the user's encrypted passwords. No reversible encryption - * is used here and I intend to keep it that way. - * - * While there are many sources of encryption outside the United - * States, it *may* be illegal to re-export reversible encryption - * computer code. Until such time as it is legal to export encryption - * software freely from the US, please do not send me any. (AGM) - */ - -/* this should have been defined in a header file.. Why wasn't it? AGM */ -extern char *crypt(const char *key, const char *salt); - -#include "md5.h" -#include "bigcrypt.-c" - -struct cfns { - const char *salt; - int len; - char * (* mdfn)(const char *key, const char *salt); -}; - -/* array of non-standard digest algorithms available */ - -#define N_MDS 1 -const static struct cfns cfn_list[N_MDS] = { - { "$1$", 3, Goodcrypt_md5 }, -}; - -static char *_pam_md(const char *key, const char *salt) -{ - char *x,*e=NULL; - int i; - - D(("called with key='%s', salt='%s'", key, salt)); - - /* check for non-standard salts */ - - for (i=0; i<N_MDS; ++i) { - if ( !strncmp(cfn_list[i].salt, salt, cfn_list[i].len) ) { - e = cfn_list[i].mdfn(key, salt); - break; - } - } - - if ( i >= N_MDS ) { - e = bigcrypt(key, salt); /* (defaults to standard algorithm) */ - } - - x = x_strdup(e); /* put e in malloc()ed memory */ - _pam_overwrite(e); /* clean up */ - return x; /* this must be deleted elsewhere */ -} - -#ifndef PWDB_NO_MD_COMPAT -static char *_pam_md_compat(const char *key, const char *salt) -{ - char *x,*e=NULL; - - D(("called with key='%s', salt='%s'", key, salt)); - - if ( !strncmp("$1$", salt, 3) ) { - e = Brokencrypt_md5(key, salt); - x = x_strdup(e); /* put e in malloc()ed memory */ - _pam_overwrite(e); /* clean up */ - } else { - x = x_strdup(""); /* called from only one place so this is safe */ - } - - return x; /* this must be deleted elsewhere */ -} -#endif /* PWDB_NO_MD_COMPAT */ diff --git a/modules/pam_pwdb/pam_unix_passwd.-c b/modules/pam_pwdb/pam_unix_passwd.-c deleted file mode 100644 index 0949af7f..00000000 --- a/modules/pam_pwdb/pam_unix_passwd.-c +++ /dev/null @@ -1,373 +0,0 @@ -/* $Id$ */ - -static const char rcsid_pass[] = -"$Id$\n" -" - PAM_PWDB password module <morgan@parc.power.net>" -; - -#include "pam_unix_pwupd.-c" - -/* passwd/salt conversion macros */ - -#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') -#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') - -/* data tokens */ - -#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS" -#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS" - -/* Implementation */ - -/* - * i64c - convert an integer to a radix 64 character - */ -static int i64c(int i) -{ - if (i < 0) - return ('.'); - else if (i > 63) - return ('z'); - if (i == 0) - return ('.'); - if (i == 1) - return ('/'); - if (i >= 2 && i <= 11) - return ('0' - 2 + i); - if (i >= 12 && i <= 37) - return ('A' - 12 + i); - if (i >= 38 && i <= 63) - return ('a' - 38 + i); - return ('\0'); -} - -/* - * FUNCTION: _pam_unix_chauthtok() - * - * this function works in two passes. The first, when UNIX__PRELIM is - * set, obtains the previous password. It sets the PAM_OLDAUTHTOK item - * or stores it as a data item. The second function obtains a new - * password (verifying if necessary, that the user types it the same a - * second time.) depending on the 'ctrl' flags this new password may - * be stored in the PAM_AUTHTOK item or a private data item. - * - * Having obtained a new password. The function updates the - * /etc/passwd (and optionally the /etc/shadow) file(s). - * - * Provision is made for the creation of a blank shadow file if none - * is available, but one is required to update the shadow file -- the - * intention being for shadow passwords to be seamlessly implemented - * from the generic UNIX scheme. -- THIS BIT IS PRE-ALPHA.. and included - * in this release (.52) mostly for the purpose of discussion. - */ - -static int _unix_chauthtok(pam_handle_t *pamh, unsigned int ctrl) -{ - int retval; - unsigned int lctrl; - - /* <DO NOT free() THESE> */ - const char *user; - const char *pass_old, *pass_new; - /* </DO NOT free() THESE> */ - - D(("called")); - - /* - * First get the name of a user - */ - - retval = _unix_get_user( pamh, ctrl, "Username: ", &user ); - if ( retval != PAM_SUCCESS ) { - if ( on(UNIX_DEBUG,ctrl) ) { - _log_err(LOG_DEBUG, "password - could not identify user"); - } - return retval; - } - - if ( on(UNIX__PRELIM, ctrl) ) { - /* - * obtain and verify the current password (OLDAUTHTOK) for - * the user. - */ - - char *Announce; - - D(("prelim check")); - - if ( _unix_blankpasswd(ctrl, user) ) { - - return PAM_SUCCESS; - - } else if ( off(UNIX__IAMROOT, ctrl) ) { - - /* instruct user what is happening */ -#define greeting "Changing password for " - Announce = (char *) malloc(sizeof(greeting)+strlen(user)); - if (Announce == NULL) { - _log_err(LOG_CRIT, "password - out of memory"); - return PAM_BUF_ERR; - } - (void) strcpy(Announce, greeting); - (void) strcpy(Announce+sizeof(greeting)-1, user); -#undef greeting - - lctrl = ctrl; - set(UNIX__OLD_PASSWD, lctrl); - retval = _unix_read_password( pamh, lctrl - , Announce - , "(current) UNIX password: " - , NULL - , _UNIX_OLD_AUTHTOK - , &pass_old ); - free(Announce); - - if ( retval != PAM_SUCCESS ) { - _log_err(LOG_NOTICE - , "password - (old) token not obtained"); - return retval; - } - - /* verify that this is the password for this user */ - - retval = _unix_verify_password(pamh, user, pass_old, ctrl); - } else { - D(("process run by root so do nothing this time around")); - pass_old = NULL; - retval = PAM_SUCCESS; /* root doesn't have too */ - } - - if ( retval != PAM_SUCCESS ) { - D(("Authentication failed")); - pass_old = NULL; - return retval; - } - - retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); - pass_old = NULL; - if ( retval != PAM_SUCCESS ) { - _log_err(LOG_CRIT, "failed to set PAM_OLDAUTHTOK"); - } - - } else if ( on( UNIX__UPDATE, ctrl ) ) { - /* tpass is used below to store the _pam_md() return; it - * should be _pam_delete()'d. */ - - char *tpass=NULL; - - /* - * obtain the proposed password - */ - - D(("do update")); - - /* - * get the old token back. NULL was ok only if root [at this - * point we assume that this has already been enforced on a - * previous call to this function]. - */ - - if ( off(UNIX_NOT_SET_PASS, ctrl) ) { - retval = pam_get_item(pamh, PAM_OLDAUTHTOK - , (const void **)&pass_old); - } else { - retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK - , (const void **)&pass_old); - if (retval == PAM_NO_MODULE_DATA) { - retval = PAM_SUCCESS; - pass_old = NULL; - } - } - - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, "user not authenticated"); - return retval; - } - - D(("get new password now")); - - lctrl = ctrl; - - /* - * use_authtok is to force the use of a previously entered - * password -- needed for pluggable password strength checking - */ - - if ( on(UNIX_USE_AUTHTOK, lctrl) ) { - set(UNIX_USE_FIRST_PASS, lctrl); - } - - retval = _unix_read_password( pamh, lctrl - , NULL - , "Enter new UNIX password: " - , "Retype new UNIX password: " - , _UNIX_NEW_AUTHTOK - , &pass_new ); - - if ( retval != PAM_SUCCESS ) { - if ( on(UNIX_DEBUG,ctrl) ) { - _log_err(LOG_ALERT - , "password - new password not obtained"); - } - pass_old = NULL; /* tidy up */ - return retval; - } - - D(("returned to _unix_chauthtok")); - - /* - * At this point we know who the user is and what they - * propose as their new password. Verify that the new - * password is acceptable. - */ - - if (pass_new[0] == '\0') { /* "\0" password = NULL */ - pass_new = NULL; - } - - retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); - - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, "new password not acceptable"); - pass_new = pass_old = NULL; /* tidy up */ - return retval; - } - - /* - * By reaching here we have approved the passwords and must now - * rebuild the password database file. - * - * This includes the fact that the password is _not_ NULL. - */ - - /* - * First we encrypt the new password. - * - * XXX - this is where we might need some code for RADIUS types - * of password handling... no encryption needed.. - */ - - if ( on(UNIX_MD5_PASS, ctrl) ) { - - /* - * Code lifted from Marek Michalkiewicz's shadow suite. (CG) - * removed use of static variables (AGM) - */ - - struct timeval tv; - MD5_CTX ctx; - unsigned char result[16]; - char *cp = (char *)result; - unsigned char tmp[16]; - int i; - - GoodMD5Init(&ctx); - gettimeofday(&tv, (struct timezone *) 0); - GoodMD5Update(&ctx, (void *) &tv, sizeof tv); - i = getpid(); - GoodMD5Update(&ctx, (void *) &i, sizeof i); - i = clock(); - GoodMD5Update(&ctx, (void *) &i, sizeof i); - GoodMD5Update(&ctx, result, sizeof result); - GoodMD5Final(tmp, &ctx); - strcpy(cp, "$1$"); /* magic for the MD5 */ - cp += strlen(cp); - for (i = 0; i < 8; i++) - *cp++ = i64c(tmp[i] & 077); - *cp = '\0'; - - /* no longer need cleartext */ - pass_new = tpass = _pam_md(pass_new, (const char *)result); - - } else { - /* - * Salt manipulation is stolen from Rick Faith's passwd - * program. Sorry Rick :) -- alex - */ - - time_t tm; - char salt[3]; - - time(&tm); - salt[0] = bin_to_ascii(tm & 0x3f); - salt[1] = bin_to_ascii((tm >> 6) & 0x3f); - salt[2] = '\0'; - - if ( off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8 ) { - /* to avoid using the _extensions_ of the bigcrypt() - function we truncate the newly entered password */ - char *temp = malloc(9); - - if (temp == NULL) { - _log_err(LOG_CRIT, "out of memory for password"); - pass_new = pass_old = NULL; /* tidy up */ - return PAM_BUF_ERR; - } - - /* copy first 8 bytes of password */ - strncpy(temp, pass_new, 8); - temp[8] = '\0'; - - /* no longer need cleartext */ - pass_new = tpass = _pam_md( temp, salt ); - - _pam_delete(temp); /* tidy up */ - } else { - /* no longer need cleartext */ - pass_new = tpass = _pam_md( pass_new, salt ); - } - } - - D(("password processed")); - - /* update the password database(s) -- race conditions..? */ - - retval = unix_update_db(pamh, ctrl, user, pass_old, pass_new); - pass_old = pass_new = NULL; - - } else { /* something has broken with the module */ - - _log_err(LOG_ALERT, "password received unknown request"); - retval = PAM_ABORT; - - } - - return retval; -} - -/* ****************************************************************** - * Copyright (c) Alexander O. Yuriev (alex@bach.cis.temple.edu), 1996. - * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996, 1997. - * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/pam_unix_pwupd.-c b/modules/pam_pwdb/pam_unix_pwupd.-c deleted file mode 100644 index 0f646369..00000000 --- a/modules/pam_pwdb/pam_unix_pwupd.-c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * $Id$ - * - * This file contains the routines to update the passwd databases. - */ - -/* Implementation */ - -static int unix_update_db(pam_handle_t *pamh, int ctrl, const char *user, - const char *pass_old, const char *pass_new) -{ - const struct pwdb *pw=NULL; - const struct pwdb_entry *pwe=NULL; - pwdb_flag flag; - int retval, i; - - D(("called.")); - - /* obtain default user record */ - - retval = pwdb_locate("user", PWDB_DEFAULT, user, PWDB_ID_UNKNOWN, &pw); - if (retval == PWDB_PASS_PHRASE_REQD) { - retval = pwdb_set_entry(pw, "pass_phrase" - , pass_old, 1+strlen(pass_old) - , NULL, NULL, 0); - if (retval == PWDB_SUCCESS) - retval = pwdb_locate("user", pw->source, user - , PWDB_ID_UNKNOWN, &pw); - } - pass_old = NULL; - - if ( retval != PWDB_SUCCESS ) { - _log_err(LOG_ALERT, "cannot identify user %s (uid=%d)" - , user, getuid() ); - pass_new = NULL; - if (pw) - (void) pwdb_delete(&pw); - return PAM_USER_UNKNOWN; - } - - /* check that we can update all of the default databases */ - - retval = pwdb_flags("user", pw->source, &flag); - - if ( retval != PWDB_SUCCESS || ( pwdb_on(flag,PWDB_F_NOUPDATE) ) ) { - _log_err(LOG_ERR, "cannot update default database for user %s" - , user ); - pass_new = NULL; - if (pw) - (void) pwdb_delete(&pw); - return PAM_PERM_DENIED; - } - - /* If there was one, we delete the "last_change" entry */ - retval = pwdb_get_entry(pw, "last_change", &pwe); - if (retval == PWDB_SUCCESS) { - (void) pwdb_entry_delete(&pwe); - pwdb_set_entry(pw, "last_change", NULL, -1, NULL, NULL, 0); - } - - /* - * next check for pam.conf specified databases: shadow etc... [In - * other words, pam.conf indicates which database the password is - * to be subsequently placed in: this is password migration]. - */ - - if ( on(UNIX__SET_DB, ctrl) ) { - const char *db_token; - pwdb_type pt = _PWDB_MAX_TYPES; - - if ( on(UNIX_UNIX, ctrl) ) { - db_token = "U"; /* XXX - should be macro */ - pt = PWDB_UNIX; - } else if ( on(UNIX_SHADOW, ctrl) ) { - db_token = "x"; /* XXX - should be macro */ - pt = PWDB_SHADOW; - } else if ( on(UNIX_RADIUS, ctrl) ) { - db_token = "R"; /* XXX - is this ok? */ - pt = PWDB_RADIUS; - } else { - _log_err(LOG_ALERT - , "cannot determine database to use for authtok"); - pass_new = NULL; - if (pw) - (void) pwdb_delete(&pw); - return PAM_ABORT; /* we're in trouble */ - } - - /* - * Attempt to update the indicated database (only) - */ - - { - pwdb_type tpt[2]; - tpt[0] = pt; - tpt[1] = _PWDB_MAX_TYPES; - - /* Can we set entry in database? */ - retval = pwdb_flags("user", tpt, &flag); - if (retval == PWDB_SUCCESS && !pwdb_on(flag,PWDB_F_NOUPDATE)) { - /* YES. This database is available.. */ - - /* Only update if it is not already in the default list */ - for (i=0; pw->source[i] != _PWDB_MAX_TYPES - && pw->source[i] != pt ; ++i); - if (pw->source[i] == _PWDB_MAX_TYPES) { - const struct pwdb *tpw=NULL; - - /* copy database entry */ - if ((retval = pwdb_new(&tpw, 10)) != PWDB_SUCCESS - || (retval = pwdb_merge(tpw, pw, PWDB_TRUE)) - != PWDB_SUCCESS) { - _log_err(LOG_CRIT, "failed to obtain new pwdb: %s" - , pwdb_strerror(retval)); - retval = PAM_ABORT; - } else - retval = PAM_SUCCESS; - - /* set db_token */ - if (retval == PAM_SUCCESS) { - retval = pwdb_set_entry(tpw, "defer_pass", db_token - , 1+strlen(db_token) - , NULL, NULL, 0); - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "set defer_pass -> %s" - , pwdb_strerror(retval)); - retval = PAM_PERM_DENIED; - } else - retval = PAM_SUCCESS; - } - - /* update specific database */ - if (retval == PAM_SUCCESS) { - retval = pwdb_replace("user", tpt - , user, PWDB_ID_UNKNOWN, &tpw); - if (retval != PWDB_SUCCESS) { - const char *service=NULL; - (void) pam_get_item(pamh, PAM_SERVICE - , (const void **)&service); - _log_err(LOG_ALERT - , "(%s) specified database failed: %s" - , service - , pwdb_strerror(retval)); - retval = PAM_PERM_DENIED; - } else { - retval = PAM_SUCCESS; - } - } - - /* clean up temporary pwdb */ - if (tpw) - (void) pwdb_delete(&tpw); - } - - /* we can properly adopt new defer_pass */ - if (retval == PAM_SUCCESS) { - /* failing here will mean we go back to former - password location */ - (void) pwdb_set_entry(pw, "defer_pass", db_token - , 1+strlen(db_token), NULL, NULL, 0); - } - } - } - } - - /* - * the password will now be placed in appropriate (perhaps original) db - */ - - retval = pwdb_get_entry(pw, "uid", &pwe); - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "no uid!? (%s); %s", user, pwdb_strerror(retval)); - pass_new = NULL; - if (pw) - (void) pwdb_delete(&pw); - return PAM_USER_UNKNOWN; - } - - /* insert the passwd into the 'pw' structure */ - - retval = pwdb_set_entry(pw, "passwd", pass_new, 1+strlen(pass_new) - , NULL, NULL, 0); - pass_new = NULL; - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "set2 failed; %s", pwdb_strerror(retval)); - if (pw) - (void) pwdb_delete(&pw); - return PAM_AUTHTOK_LOCK_BUSY; - } - - retval = pwdb_replace("user", pw->source, user - , *((uid_t *)pwe->value), &pw); - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "user (%s/%d) update failed; %s" - , user, *((uid_t *)pwe->value), pwdb_strerror(retval)); - if (pw) - (void) pwdb_delete(&pw); - (void) pwdb_entry_delete(&pwe); - return PAM_ABORT; - } - - if (retval != PWDB_SUCCESS) { - - _log_err(LOG_ALERT, "user (%s/%d) update failed; %s" - , user, *((uid_t *)pwe->value), pwdb_strerror(retval)); - retval = PAM_ABORT; - - } else { - /* password updated */ - - _log_err(LOG_INFO, "password for (%s/%d) changed by (%s/%d)" - , user, *((uid_t *)pwe->value), getlogin(), getuid()); - retval = PAM_SUCCESS; - } - - /* tidy up */ - - (void) pwdb_entry_delete(&pwe); - if (pw) - (void) pwdb_delete(&pw); - - return retval; -} - -/* ****************************************************************** - * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996,1997. - * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997. - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/pam_unix_sess.-c b/modules/pam_pwdb/pam_unix_sess.-c deleted file mode 100644 index 8f862eae..00000000 --- a/modules/pam_pwdb/pam_unix_sess.-c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Id$ - * - * See end for Copyright information - */ - -static const char rcsid_sess[] = -"$Id$\n" -" - PAM_PWDB session management. morgan@parc.power.net"; - -/* Define internal functions */ - -static int _unix_open_session(pam_handle_t *pamh, unsigned int ctrl) -{ - int retval; - char *user_name, *service; - - D(("called.")); - - retval = pam_get_item( pamh, PAM_USER, (void *) &user_name ); - if ( user_name == NULL || retval != PAM_SUCCESS ) { - _log_err(LOG_CRIT, "open_session - error recovering username"); - return PAM_SESSION_ERR; - } - - retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service ); - if ( service == NULL || retval != PAM_SUCCESS ) { - _log_err(LOG_CRIT, "open_session - error recovering service"); - return PAM_SESSION_ERR; - } - - _log_err(LOG_INFO, "(%s) session opened for user %s by %s(uid=%d)" - , service, user_name - , getlogin() == NULL ? "":getlogin(), getuid() ); - - return PAM_SUCCESS; -} - -static int _unix_close_session(pam_handle_t *pamh, unsigned int ctrl) -{ - int retval; - char *user_name, *service; - - D(("called.")); - - retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); - if ( user_name == NULL || retval != PAM_SUCCESS ) { - _log_err(LOG_CRIT, "close_session - error recovering username"); - return PAM_SESSION_ERR; - } - - retval = pam_get_item( pamh, PAM_SERVICE, (void*) &service ); - if ( service == NULL || retval != PAM_SUCCESS ) { - _log_err(LOG_CRIT, "close_session - error recovering service"); - return PAM_SESSION_ERR; - } - - _log_err(LOG_INFO, "(%s) session closed for user %s" - , service, user_name ); - - return PAM_SUCCESS; -} - -/* - * Copyright (c) Alexander O. Yuriev, 1996. All rights reserved. - * Copyright (c) Andrew G. Morgan, 1996, <morgan@parc.power.net> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/pwdb_chkpwd.c b/modules/pam_pwdb/pwdb_chkpwd.c deleted file mode 100644 index e4fe38f8..00000000 --- a/modules/pam_pwdb/pwdb_chkpwd.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * $Id$ - * - * This program is designed to run setuid(root) or with sufficient - * privilege to read all of the unix password databases. It is designed - * to provide a mechanism for the current user (defined by this - * process' real uid) to verify their own password. - * - * The password is read from the standard input. The exit status of - * this program indicates whether the user is authenticated or not. - * - * Copyright information is located at the end of the file. - * - */ - -#include <security/_pam_aconf.h> - -#ifdef MEMORY_DEBUG -# undef exit -# undef strdup -# undef free -#endif /* MEMORY_DEBUG */ - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#include <security/_pam_macros.h> - -#define MAXPASS 200 /* the maximum length of a password */ - -#define UNIX_PASSED (PWDB_SUCCESS) -#define UNIX_FAILED (PWDB_SUCCESS+1) - -#include <pwdb/pwdb_public.h> - -/* syslogging function for errors and other information */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("pwdb_chkpwd", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -#define PWDB_NO_MD_COMPAT -#include "pam_unix_md.-c" - -static int _unix_verify_passwd(const char *salt, const char *p) -{ - char *pp=NULL; - int retval; - - if (p == NULL) { - if (*salt == '\0') { - retval = UNIX_PASSED; - } else { - retval = UNIX_FAILED; - } - } else { - pp = _pam_md(p, salt); - p = NULL; /* no longer needed here */ - - if ( strcmp( pp, salt ) == 0 ) { - retval = UNIX_PASSED; - } else { - retval = UNIX_FAILED; - } - } - - /* clean up */ - { - char *tp = pp; - if (pp != NULL) { - while(tp && *tp) - *tp++ = '\0'; - free(pp); - pp = tp = NULL; - } - } - - return retval; -} - -int main(int argc, char **argv) -{ - const struct pwdb *pw=NULL; - const struct pwdb_entry *pwe=NULL; - char pass[MAXPASS+1]; - int npass, force_failure=0; - int retval=UNIX_FAILED; - - /* - * we establish that this program is running with non-tty stdin. - * this is to discourage casual use. It does *NOT* prevent an - * intruder from repeatadly running this program to determine the - * password of the current user (brute force attack, but one for - * which the attacker must already have gained access to the user's - * account). - */ - - if ( isatty(STDIN_FILENO) ) { - _log_err(LOG_NOTICE - , "inappropriate use of PWDB helper binary [UID=%d]" - , getuid() ); - fprintf(stderr, - "This program is not designed for running in this way\n" - "-- the system administrator has been informed\n"); - exit(UNIX_FAILED); - } - - /* - * determine the current user's name: - */ - - retval = pwdb_start(); - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "failed to open pwdb"); - retval = UNIX_FAILED; - } - if (retval != UNIX_FAILED) { - retval = pwdb_locate("user", PWDB_DEFAULT, PWDB_NAME_UNKNOWN, - getuid(), &pw); - } - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "could not identify user"); - while (pwdb_end() != PWDB_SUCCESS); - exit(UNIX_FAILED); - } - if (argc == 2) { - if (pwdb_get_entry(pw, "user", &pwe) == PWDB_SUCCESS) { - if (pwe == NULL) { - force_failure = 1; - } else { - if (strcmp((const char *) pwe->value, argv[1])) { - force_failure = 1; - } - pwdb_entry_delete(&pwe); - } - } - } - - /* read the password from stdin (a pipe from the pam_pwdb module) */ - - npass = read(STDIN_FILENO, pass, MAXPASS); - - if (npass < 0) { /* is it a valid password? */ - _log_err(LOG_DEBUG, "no password supplied"); - retval = UNIX_FAILED; - } else if (npass >= MAXPASS-1) { - _log_err(LOG_DEBUG, "password too long"); - retval = UNIX_FAILED; - } else if (pwdb_get_entry(pw, "passwd", &pwe) != PWDB_SUCCESS) { - _log_err(LOG_WARNING, "password not found"); - retval = UNIX_FAILED; - } else { - if (npass <= 0) { - /* the password is NULL */ - - retval = _unix_verify_passwd((const char *)(pwe->value), NULL); - } else { - /* does pass agree with the official one? */ - - pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_passwd((const char *)(pwe->value), pass); - } - } - - memset(pass, '\0', MAXPASS); /* clear memory of the password */ - while (pwdb_end() != PWDB_SUCCESS); - - if ((retval != UNIX_FAILED) && force_failure) { - retval = UNIX_FAILED; - } - - /* return pass or fail */ - - exit(retval); -} - -/* - * Copyright (c) Andrew G. Morgan, 1997. All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_pwdb/support.-c b/modules/pam_pwdb/support.-c deleted file mode 100644 index e6d5829d..00000000 --- a/modules/pam_pwdb/support.-c +++ /dev/null @@ -1,943 +0,0 @@ -/* - * $Id$ - * - * Copyright information at end of file. - */ - -/* - * here is the string to inform the user that the new passwords they - * typed were not the same. - */ - -#define MISTYPED_PASS "Sorry, passwords do not match" - -/* type definition for the control options */ - -typedef struct { - const char *token; - unsigned int mask; /* shall assume 32 bits of flags */ - unsigned int flag; -} UNIX_Ctrls; - -/* - * macro to determine if a given flag is on - */ - -#define on(x,ctrl) (unix_args[x].flag & ctrl) - -/* - * macro to determine that a given flag is NOT on - */ - -#define off(x,ctrl) (!on(x,ctrl)) - -/* - * macro to turn on/off a ctrl flag manually - */ - -#define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag) -#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag)) - -/* the generic mask */ - -#define _ALL_ON_ (~0U) - -/* end of macro definitions definitions for the control flags */ - -/* ****************************************************************** * - * ctrl flags proper.. - */ - -/* - * here are the various options recognized by the unix module. They - * are enumerated here and then defined below. Internal arguments are - * given NULL tokens. - */ - -#define UNIX__OLD_PASSWD 0 /* internal */ -#define UNIX__VERIFY_PASSWD 1 /* internal */ -#define UNIX__IAMROOT 2 /* internal */ - -#define UNIX_AUDIT 3 /* print more things than debug.. - some information may be sensitive */ -#define UNIX_USE_FIRST_PASS 4 -#define UNIX_TRY_FIRST_PASS 5 -#define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */ - -#define UNIX__PRELIM 7 /* internal */ -#define UNIX__UPDATE 8 /* internal */ -#define UNIX__NONULL 9 /* internal */ -#define UNIX__QUIET 10 /* internal */ -#define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */ -#define UNIX_SHADOW 12 /* signal shadow on */ -#define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */ -#define UNIX__NULLOK 14 /* Null token ok */ -#define UNIX_RADIUS 15 /* wish to use RADIUS for password */ -#define UNIX__SET_DB 16 /* internal - signals redirect to db */ -#define UNIX_DEBUG 17 /* send more info to syslog(3) */ -#define UNIX_NODELAY 18 /* admin does not want a fail-delay */ -#define UNIX_UNIX 19 /* wish to use /etc/passwd for pwd */ -#define UNIX_BIGCRYPT 20 /* use DEC-C2 crypt()^x function */ -#define UNIX_LIKE_AUTH 21 /* need to auth for setcred to work */ -/* -------------- */ -#define UNIX_CTRLS_ 22 /* number of ctrl arguments defined */ - - -static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = { -/* symbol token name ctrl mask ctrl * - * ------------------ ------------------ -------------- ---------- */ - -/* UNIX__OLD_PASSWD */ { NULL, _ALL_ON_, 01 }, -/* UNIX__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 }, -/* UNIX__IAMROOT */ { NULL, _ALL_ON_, 04 }, -/* UNIX_AUDIT */ { "audit", _ALL_ON_, 010 }, -/* UNIX_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(060), 020 }, -/* UNIX_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(060), 040 }, -/* UNIX_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 0100 }, -/* UNIX__PRELIM */ { NULL, _ALL_ON_^(0600), 0200 }, -/* UNIX__UPDATE */ { NULL, _ALL_ON_^(0600), 0400 }, -/* UNIX__NONULL */ { NULL, _ALL_ON_, 01000 }, -/* UNIX__QUIET */ { NULL, _ALL_ON_, 02000 }, -/* UNIX_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 04000 }, -/* UNIX_SHADOW */ { "shadow", _ALL_ON_^(0140000), 010000 }, -/* UNIX_MD5_PASS */ { "md5", _ALL_ON_^(02000000), 020000 }, -/* UNIX__NULLOK */ { "nullok", _ALL_ON_^(01000), 0 }, -/* UNIX_RADIUS */ { "radius", _ALL_ON_^(0110000), 040000 }, -/* UNIX__SET_DB */ { NULL, _ALL_ON_, 0100000 }, -/* UNIX_DEBUG */ { "debug", _ALL_ON_, 0200000 }, -/* UNIX_NODELAY */ { "nodelay", _ALL_ON_, 0400000 }, -/* UNIX_UNIX */ { "unix", _ALL_ON_^(050000), 01000000 }, -/* UNIX_BIGCRYPT */ { "bigcrypt", _ALL_ON_^(020000), 02000000 }, -/* UNIX_LIKE_AUTH */ { "likeauth", _ALL_ON_, 04000000 }, -}; - -#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) - -/* syslogging function for errors and other information */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM_pwdb", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* this is a front-end for module-application conversations */ - -static int converse(pam_handle_t *pamh, int ctrl, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { - - retval = conv->conv(nargs, ( const struct pam_message ** ) message - , response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && on(UNIX_DEBUG,ctrl) ) { - _log_err(LOG_DEBUG, "conversation failure [%s]" - , pam_strerror(pamh, retval)); - } - - } else if (retval != PAM_CONV_AGAIN) { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - , pam_strerror(pamh, retval)); - } - - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -static int make_remark(pam_handle_t *pamh, unsigned int ctrl - , int type, const char *text) -{ - int retval=PAM_SUCCESS; - - if ( off(UNIX__QUIET, ctrl) ) { - struct pam_message *pmsg[1], msg[1]; - struct pam_response *resp; - - pmsg[0] = &msg[0]; - msg[0].msg = text; - msg[0].msg_style = type; - - resp = NULL; - retval = converse(pamh, ctrl, 1, pmsg, &resp); - - if (resp) { - _pam_drop_reply(resp, 1); - } - } - return retval; -} - -/* - * set the control flags for the UNIX module. - */ - -static int set_ctrl(int flags, int argc, const char **argv) -{ - unsigned int ctrl; - - D(("called.")); - - ctrl = UNIX_DEFAULTS; /* the default selection of options */ - - /* set some flags manually */ - - if ( getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK) ) { - set(UNIX__IAMROOT, ctrl); - } - if ( flags & PAM_UPDATE_AUTHTOK ) { - set(UNIX__UPDATE, ctrl); - } - if ( flags & PAM_PRELIM_CHECK ) { - set(UNIX__PRELIM, ctrl); - } - if ( flags & PAM_DISALLOW_NULL_AUTHTOK ) { - set(UNIX__NONULL, ctrl); - } - if ( flags & PAM_SILENT ) { - set(UNIX__QUIET, ctrl); - } - - /* now parse the arguments to this module */ - - while (argc-- > 0) { - int j; - - D(("pam_pwdb arg: %s",*argv)); - - for (j=0; j<UNIX_CTRLS_; ++j) { - if (unix_args[j].token - && ! strcmp(*argv, unix_args[j].token) ) { - break; - } - } - - if ( j >= UNIX_CTRLS_ ) { - _log_err(LOG_ERR, "unrecognized option [%s]",*argv); - } else { - ctrl &= unix_args[j].mask; /* for turning things off */ - ctrl |= unix_args[j].flag; /* for turning things on */ - } - - ++argv; /* step to next argument */ - } - - /* these are used for updating passwords in specific places */ - - if (on(UNIX_SHADOW,ctrl) || on(UNIX_RADIUS,ctrl) || on(UNIX_UNIX,ctrl)) { - set(UNIX__SET_DB, ctrl); - } - - /* auditing is a more sensitive version of debug */ - - if ( on(UNIX_AUDIT,ctrl) ) { - set(UNIX_DEBUG, ctrl); - } - - /* return the set of flags */ - - D(("done.")); - return ctrl; -} - -/* use this to free strings. ESPECIALLY password strings */ - -static char *_pam_delete(register char *xx) -{ - _pam_overwrite(xx); - _pam_drop(xx); - return NULL; -} - -static void _cleanup(pam_handle_t *pamh, void *x, int error_status) -{ - x = _pam_delete( (char *) x ); -} - -/* ************************************************************** * - * Useful non-trivial functions * - * ************************************************************** */ - -#include "pam_unix_md.-c" - -/* - * the following is used to keep track of the number of times a user fails - * to authenticate themself. - */ - -#define FAIL_PREFIX "-UN*X-FAIL-" -#define UNIX_MAX_RETRIES 3 - -struct _pam_failed_auth { - char *user; /* user that's failed to be authenticated */ - char *name; /* attempt from user with name */ - int id; /* uid of name'd user */ - int count; /* number of failures so far */ -}; - -#ifndef PAM_DATA_REPLACE -#error "Need to get an updated libpam 0.52 or better" -#endif - -static void _cleanup_failures(pam_handle_t *pamh, void *fl, int err) -{ - int quiet; - const char *service=NULL; - struct _pam_failed_auth *failure; - - D(("called")); - - quiet = err & PAM_DATA_SILENT; /* should we log something? */ - err &= PAM_DATA_REPLACE; /* are we just replacing data? */ - failure = (struct _pam_failed_auth *) fl; - - if ( failure != NULL ) { - - if ( !quiet && !err ) { /* under advisement from Sun,may go away */ - - /* log the number of authentication failures */ - if ( failure->count > 1 ) { - (void) pam_get_item(pamh, PAM_SERVICE - , (const void **)&service); - _log_err(LOG_NOTICE - , "%d more authentication failure%s; %s(uid=%d) -> " - "%s for %s service" - , failure->count-1, failure->count==2 ? "":"s" - , failure->name - , failure->id - , failure->user - , service == NULL ? "**unknown**":service - ); - if ( failure->count > UNIX_MAX_RETRIES ) { - _log_err(LOG_ALERT - , "service(%s) ignoring max retries; %d > %d" - , service == NULL ? "**unknown**":service - , failure->count - , UNIX_MAX_RETRIES ); - } - } - } - failure->user = _pam_delete(failure->user); /* tidy up */ - failure->name = _pam_delete(failure->name); /* tidy up */ - free(failure); - } -} - -/* - * verify the password of a user - */ - -#include <sys/types.h> -#include <sys/wait.h> - -static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd, - const char *user) -{ - int retval, child, fds[2]; - - D(("called.")); - /* create a pipe for the password */ - if (pipe(fds) != 0) { - D(("could not make pipe")); - return PAM_AUTH_ERR; - } - - /* fork */ - child = fork(); - if (child == 0) { - static char *args[] = { NULL, NULL, NULL }; - static char *envp[] = { NULL }; - - /* XXX - should really tidy up PAM here too */ - while (pwdb_end() == PWDB_SUCCESS); - - /* reopen stdin as pipe */ - close(fds[1]); - dup2(fds[0], STDIN_FILENO); - - /* exec binary helper */ - args[0] = x_strdup(CHKPWD_HELPER); - args[1] = x_strdup(user); - - execve(CHKPWD_HELPER, args, envp); - - /* should not get here: exit with error */ - D(("helper binary is not available")); - exit(PWDB_SUCCESS+1); - } else if (child > 0) { - /* wait for child */ - if (passwd != NULL) { /* send the password to the child */ - write(fds[1], passwd, strlen(passwd)+1); - passwd = NULL; - } else { - write(fds[1], "", 1); /* blank password */ - } - close(fds[0]); /* we close this after the write because we want - to avoid a possible SIGPIPE. */ - close(fds[1]); - (void) waitpid(child, &retval, 0); /* wait for helper to complete */ - retval = (retval == PWDB_SUCCESS) ? PAM_SUCCESS:PAM_AUTH_ERR; - } else { - D(("fork failed")); - retval = PAM_AUTH_ERR; - } - - D(("returning %d", retval)); - return retval; -} - -static int _unix_verify_password(pam_handle_t *pamh, const char *name, - const char *p, unsigned int ctrl) -{ - const struct pwdb *pw=NULL; - const struct pwdb_entry *pwe=NULL; - - const char *salt; - char *pp; - char *data_name; - int retval; - int verify_result; - - D(("called")); - -#ifdef HAVE_PAM_FAIL_DELAY - if ( off(UNIX_NODELAY, ctrl) ) { - D(("setting delay")); - (void) pam_fail_delay(pamh, 1000000); /* 1 sec delay for on failure */ - } -#endif - - /* locate the entry for this user */ - - D(("locating user's record")); - retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw); - if (retval == PWDB_PASS_PHRASE_REQD) { - /* - * give the password to the pwdb library. It may be needed to - * access the database - */ - - retval = pwdb_set_entry( pw, "pass_phrase", p, 1+strlen(p) - , NULL, NULL, 0); - if (retval != PWDB_SUCCESS) { - _log_err(LOG_ALERT, "find pass; %s", pwdb_strerror(retval)); - (void) pwdb_delete(&pw); - p = NULL; - return PAM_CRED_INSUFFICIENT; - } - - retval = pwdb_locate("user", pw->source, name, PWDB_ID_UNKNOWN, &pw); - } - - if (retval != PWDB_SUCCESS) { - D(("user's record unavailable")); - if ( on(UNIX_AUDIT, ctrl) ) { - /* this might be a typo and the user has given a password - instead of a username. Careful with this. */ - _log_err(LOG_ALERT, "check pass; user (%s) unknown", name); - } else { - _log_err(LOG_ALERT, "check pass; user unknown"); - } - (void) pwdb_delete(&pw); - p = NULL; - return PAM_USER_UNKNOWN; - } - - /* - * courtesy of PWDB the password for the user is stored in - * encrypted form in the "passwd" entry of pw. - */ - - retval = pwdb_get_entry(pw, "passwd", &pwe); - if (retval != PWDB_SUCCESS) { - if (geteuid()) { - /* we are not root perhaps this is the reason? Run helper */ - D(("running helper binary")); - retval = pwdb_run_helper_binary(pamh, p, name); - } else { - retval = PAM_AUTHINFO_UNAVAIL; - _log_err(LOG_ALERT, "get passwd; %s", pwdb_strerror(retval)); - } - (void) pwdb_delete(&pw); - p = NULL; - return retval; - } - salt = (const char *) pwe->value; - - /* - * XXX: Cristian, the above is not the case for RADIUS(?) Some - * lines should be added for RADIUS to verify the password in - * clear text... - */ - - data_name = (char *) malloc(sizeof(FAIL_PREFIX)+strlen(name)); - if ( data_name == NULL ) { - _log_err(LOG_CRIT, "no memory for data-name"); - } - strcpy(data_name, FAIL_PREFIX); - strcpy(data_name + sizeof(FAIL_PREFIX)-1, name); - - if ( !( (salt && *salt) || (p && *p) ) ) { - - D(("two null passwords to compare")); - - /* the stored password is NULL */ - pp = NULL; - if ( off(UNIX__NONULL, ctrl ) ) { /* this means we've succeeded */ - verify_result = PAM_SUCCESS; - } else { - verify_result = PAM_AUTH_ERR; - } - - } else if ( !( salt && p ) ) { - - D(("one of the two to compare are NULL")); - - pp = NULL; - verify_result = PAM_AUTH_ERR; - - } else { - - /* there is no way that p can be NULL (one can be "") */ - pp = _pam_md(p, salt); - - /* the moment of truth -- do we agree with the password? */ - D(("comparing state of pp[%s] and salt[%s]", pp, salt)); - - if ( strcmp( pp, salt ) == 0 ) { - verify_result = PAM_SUCCESS; - } else { - _pam_delete(pp); - pp = _pam_md_compat(p, salt); - if ( strcmp( pp, salt ) == 0 ) { - verify_result = PAM_SUCCESS; - } else { - verify_result = PAM_AUTH_ERR; - } - } - - p = NULL; /* no longer needed here */ - - } - - if ( verify_result == PAM_SUCCESS ) { - - retval = PAM_SUCCESS; - if (data_name) { /* reset failures */ - pam_set_data(pamh, data_name, NULL, _cleanup_failures); - } - - } else { - - retval = PAM_AUTH_ERR; - if (data_name != NULL) { - struct _pam_failed_auth *new=NULL; - const struct _pam_failed_auth *old=NULL; - - /* get a failure recorder */ - - new = (struct _pam_failed_auth *) - malloc(sizeof(struct _pam_failed_auth)); - - if (new != NULL) { - - new->user = x_strdup(name); - new->id = getuid(); - new->name = x_strdup(getlogin() ? getlogin():"" ); - - /* any previous failures for this user ? */ - pam_get_data(pamh, data_name, (const void **)&old ); - - if (old != NULL) { - new->count = old->count +1; - if (new->count >= UNIX_MAX_RETRIES) { - retval = PAM_MAXTRIES; - } - } else { - const char *service=NULL; - (void) pam_get_item(pamh, PAM_SERVICE - , (const void **)&service); - _log_err(LOG_NOTICE - , "authentication failure; %s(uid=%d) -> " - "%s for %s service" - , new->name - , new->id - , new->user - , service == NULL ? "**unknown**":service - ); - new->count = 1; - } - - pam_set_data(pamh, data_name, new, _cleanup_failures); - - } else { - _log_err(LOG_CRIT, "no memory for failure recorder"); - } - } - - } - - (void) pwdb_entry_delete(&pwe); - (void) pwdb_delete(&pw); - salt = NULL; - _pam_delete(data_name); - _pam_delete(pp); - - D(("done [%d].", retval)); - - return retval; -} - -/* - * this function obtains the name of the current user and ensures - * that the PAM_USER item is set to this value - */ - -static int _unix_get_user(pam_handle_t *pamh, unsigned int ctrl - , const char *prompt, const char **user) -{ - int retval; - - D(("called")); - - retval = pam_get_user(pamh, user, prompt); - if (retval != PAM_SUCCESS) { - D(("trouble reading username")); - return retval; - } - - /* - * Various libraries at various times have had bugs related to - * '+' or '-' as the first character of a user name. Don't take - * any chances here. Require that the username starts with an - * alphanumeric character. - */ - - if (*user == NULL || !isalnum(**user)) { - D(("bad username")); - if (on(UNIX_DEBUG,ctrl)) { - _log_err(LOG_ERR, "bad username [%s]", *user); - } - return PAM_USER_UNKNOWN; - } - - if (retval == PAM_SUCCESS && on(UNIX_DEBUG,ctrl)) { - _log_err(LOG_DEBUG, "username [%s] obtained", *user); - } - - return retval; -} - -/* - * _unix_blankpasswd() is a quick check for a blank password - * - * returns TRUE if user does not have a password - * - to avoid prompting for one in such cases (CG) - */ - -static int _unix_blankpasswd(unsigned int ctrl, const char *name) -{ - const struct pwdb *pw=NULL; - const struct pwdb_entry *pwe=NULL; - int retval; - - D(("called")); - - /* - * This function does not have to be too smart if something goes - * wrong, return FALSE and let this case to be treated somewhere - * else (CG) - */ - - if ( on(UNIX__NONULL, ctrl) ) - return 0; /* will fail but don't let on yet */ - - /* find the user's database entry */ - - retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw); - if (retval != PWDB_SUCCESS || pw == NULL ) { - - retval = 0; - - } else { - - /* Does this user have a password? */ - - retval = pwdb_get_entry(pw, "passwd", &pwe); - if ( retval != PWDB_SUCCESS || pwe == NULL ) - retval = 0; - else if ( pwe->value == NULL || ((char *)pwe->value)[0] == '\0' ) - retval = 1; - else - retval = 0; - - } - - /* tidy up */ - - if ( pw ) { - (void) pwdb_delete(&pw); - if ( pwe ) - (void) pwdb_entry_delete(&pwe); - } - - return retval; -} - -/* - * obtain a password from the user - */ - -static int _unix_read_password( pam_handle_t *pamh - , unsigned int ctrl - , const char *comment - , const char *prompt1 - , const char *prompt2 - , const char *data_name - , const char **pass ) -{ - int authtok_flag; - int retval; - const char *item; - char *token; - - D(("called")); - - /* - * make sure nothing inappropriate gets returned - */ - - *pass = token = NULL; - - /* - * which authentication token are we getting? - */ - - authtok_flag = on(UNIX__OLD_PASSWD,ctrl) ? PAM_OLDAUTHTOK:PAM_AUTHTOK ; - - /* - * should we obtain the password from a PAM item ? - */ - - if ( on(UNIX_TRY_FIRST_PASS,ctrl) || on(UNIX_USE_FIRST_PASS,ctrl) ) { - retval = pam_get_item(pamh, authtok_flag, (const void **) &item); - if (retval != PAM_SUCCESS ) { - /* very strange. */ - _log_err(LOG_ALERT - , "pam_get_item returned error to unix-read-password" - ); - return retval; - } else if (item != NULL) { /* we have a password! */ - *pass = item; - item = NULL; - return PAM_SUCCESS; - } else if (on(UNIX_USE_FIRST_PASS,ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } else if (on(UNIX_USE_AUTHTOK, ctrl) - && off(UNIX__OLD_PASSWD, ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - - /* - * getting here implies we will have to get the password from the - * user directly. - */ - - { - struct pam_message msg[3],*pmsg[3]; - struct pam_response *resp; - int i, replies; - - /* prepare to converse */ - - if ( comment != NULL && off(UNIX__QUIET, ctrl) ) { - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = comment; - i = 1; - } else { - i = 0; - } - - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt1; - replies = 1; - - if ( prompt2 != NULL ) { - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt2; - ++replies; - } - - /* so call the conversation expecting i responses */ - resp = NULL; - retval = converse(pamh, ctrl, i, pmsg, &resp); - - if (resp != NULL) { - - /* interpret the response */ - - if (retval == PAM_SUCCESS) { /* a good conversation */ - - token = x_strdup(resp[i-replies].resp); - if (token != NULL) { - if (replies == 2) { - - /* verify that password entered correctly */ - if (!resp[i-1].resp - || strcmp(token,resp[i-1].resp)) { - token = _pam_delete(token); /* mistyped */ - retval = PAM_AUTHTOK_RECOVER_ERR; - make_remark(pamh, ctrl - , PAM_ERROR_MSG, MISTYPED_PASS); - } - } - - } else { - _log_err(LOG_NOTICE - , "could not recover authentication token"); - } - - } - - /* - * tidy up the conversation (resp_retcode) is ignored - * -- what is it for anyway? AGM - */ - - _pam_drop_reply(resp, i); - - } else { - retval = (retval == PAM_SUCCESS) - ? PAM_AUTHTOK_RECOVER_ERR:retval ; - } - } - - if (retval != PAM_SUCCESS) { - if ( on(UNIX_DEBUG,ctrl) ) - _log_err(LOG_DEBUG,"unable to obtain a password"); - return retval; - } - - /* 'token' is the entered password */ - - if ( off(UNIX_NOT_SET_PASS, ctrl) ) { - - /* we store this password as an item */ - - retval = pam_set_item(pamh, authtok_flag, token); - token = _pam_delete(token); /* clean it up */ - if ( retval != PAM_SUCCESS - || (retval = pam_get_item(pamh, authtok_flag - , (const void **)&item)) - != PAM_SUCCESS ) { - - _log_err(LOG_CRIT, "error manipulating password"); - return retval; - - } - - } else { - /* - * then store it as data specific to this module. pam_end() - * will arrange to clean it up. - */ - - retval = pam_set_data(pamh, data_name, (void *) token, _cleanup); - if (retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, "error manipulating password data [%s]" - , pam_strerror(pamh, retval) ); - token = _pam_delete(token); - return retval; - } - item = token; - token = NULL; /* break link to password */ - } - - *pass = item; - item = NULL; /* break link to password */ - - return PAM_SUCCESS; -} - -static int _pam_unix_approve_pass(pam_handle_t *pamh - , unsigned int ctrl - , const char *pass_old - , const char *pass_new) -{ - D(("&new=%p, &old=%p",pass_old,pass_new)); - D(("new=[%s]",pass_new)); - D(("old=[%s]",pass_old)); - - if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { - if ( on(UNIX_DEBUG, ctrl) ) { - _log_err(LOG_DEBUG, "bad authentication token"); - } - make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? - "No password supplied":"Password unchanged" ); - return PAM_AUTHTOK_ERR; - } - - /* - * if one wanted to hardwire authentication token strength - * checking this would be the place - AGM - */ - - return PAM_SUCCESS; -} - -/* ****************************************************************** * - * Copyright (c) Andrew G. Morgan 1996-8. - * Copyright (c) Alex O. Yuriev, 1996. - * Copyright (c) Cristian Gafton 1996. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - diff --git a/modules/pam_radius/.cvsignore b/modules/pam_radius/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_radius/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_radius/Makefile b/modules/pam_radius/Makefile deleted file mode 100644 index aa149d3e..00000000 --- a/modules/pam_radius/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Cristian Gafton <gafton@redhat.com> 1996/09/10 -# -# STATIC modules are not supported -# - -include ../../Make.Rules - -TITLE=pam_radius -CONFD=$(CONFIGED)/security -export CONFD -CONFILE=$(CONFD)/radius.conf -export CONFILE - -ifeq ($(HAVE_LIBPWDB),yes) - -# - -LIBSRC = $(TITLE).c -LIBOBJ = $(TITLE).o - -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -#LIBOBJS = $(addprefix static/,$(LIBOBJ)) - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -#static/%.o : %.c -# $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - - -ifdef DYNAMIC -LIBSHARED = $(TITLE).so -endif - -#ifdef STATIC -#LIBSTATIC = lib$(TITLE).o -#endif - -####################### don't edit below ####################### - -all: dirs $(LIBSHARED) $(LIBSTATIC) register - -dirs: -ifdef DYNAMIC - $(MKDIR) ./dynamic -endif -#ifdef STATIC -# $(MKDIR) ./static -#endif - -register: -#ifdef STATIC -# ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) -#endif - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) - -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) -lpwdb -endif - -#ifdef STATIC -#$(LIBOBJS): $(LIBSRC) -# -#$(LIBSTATIC): $(LIBOBJS) -# $(LD) -r -o $@ $(LIBOBJS) -lpwdb -#endif - -install: all -ifdef DYNAMIC - $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) -endif - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so - -clean: - rm -f $(LIBOBJD) $(LIBOBJS) core *~ - rm -f *.a *.o *.so *.bak dynamic/* static/* - rm -rf dynamic static - -.c.o: - $(CC) $(CFLAGS) -c $< - -else - -include ../dont_makefile - -endif diff --git a/modules/pam_radius/README b/modules/pam_radius/README deleted file mode 100644 index 253308fd..00000000 --- a/modules/pam_radius/README +++ /dev/null @@ -1,58 +0,0 @@ - -pam_radius module: - RADIUS session module. - -WHAT IT DOES: - This module is intended to provide the session service for users -autheticated with a RADIUS server. At the present stage, the only option -supported is the use of the RADIUS server as an accounting server. There are -few things which needs to be cleared out first in the PAM project until one -will be able to use this module and expect it to magically start pppd in -response to a RADIUS server command to use PPP for this user, or to initiate -a telnet connection to another host, or to hang and call back the user using -parameters provided in the RADIUS server response. Most of these things are -better suited for the radius login application. I hope to make available -Real Soon (tm) patches for the login apps to make it work this way. - - -ARGUMENTS RECOGNIZED: - debug verbose logging - -MODULE SERVICES PROVIDED: - session _open_session and _close_session - - When opening a session, this module sends an Accounting-Start -message to the RADIUS server, which will log/update/whatever a database for -this user. On close, an Accounting-Stop message is sent to the RADIUS -server. - -This module have no other pre-requisites for making it work. One can install -a RADIUS server just for fun and use it as a centralized accounting server and -forget about wtmp/last/sac&comp :-) - -USAGE: - For the services you need this module (login for example) put - the following line in /etc/pam.conf as the last line for that - service (usually after the pam_unix session line): - - login session required /lib/security/pam_radius.so - - Replace "login" for each service you are using this module. - - This module make extensive use of the API provided in libpwdb - 0.54preB or later. By default, it will read the radius server - configuration (hostname and secret) from /etc/raddb/server. This is - a default compiled into libpwdb, and curently there is no way to - modify this default without recompiling libpwdb. I am working on - extending the radius support from libpwdb to provide a possibility - to make this runtime-configurable. - - Also please note that libpwdb will require also the RADIUS - dictionary to be present (/etc/raddb/dictionary). - -TODO: - The work is far from complete. Deal with "real" session things. - -AUTHOR: - Cristian Gafton <gafton@redhat.com> - diff --git a/modules/pam_radius/pam_radius.c b/modules/pam_radius/pam_radius.c deleted file mode 100644 index b412edf9..00000000 --- a/modules/pam_radius/pam_radius.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * pam_radius - * Process an user session according to a RADIUS server response - * - * 1.0 - initial release - Linux ONLY - * 1.1 - revised and reorganized for libpwdb 0.54preB or higher - * - removed the conf= parameter, since we use libpwdb exclusively now - * - * See end for Copyright information - */ - -#if !(defined(linux)) -#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! -#endif - -/* Module defines */ -#define BUFFER_SIZE 1024 -#define LONG_VAL_PTR(ptr) ((*(ptr)<<24)+(*((ptr)+1)<<16)+(*((ptr)+2)<<8)+(*((ptr)+3))) - -#define PAM_SM_SESSION - -#include "pam_radius.h" - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -static time_t session_time; - -/* we need to save these from open_session to close_session, since - * when close_session will be called we won't be root anymore and - * won't be able to access again the radius server configuration file - * -- cristiang */ - -static RADIUS_SERVER rad_server; -static char hostname[BUFFER_SIZE]; -static char secret[BUFFER_SIZE]; - -/* logging */ -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("pam_radius", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 - -static int _pam_parse(int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -/* now the session stuff */ -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval; - char *user_name; - int ctrl; - - ctrl = _pam_parse(argc, argv); - retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); - if ( user_name == NULL || retval != PAM_SUCCESS ) { - _pam_log(LOG_CRIT, "open_session - error recovering username"); - return PAM_SESSION_ERR; - } - - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "starting RADIUS user session for '%s'", - user_name); - - retval = get_server_entries(hostname, secret); - if ((retval != PWDB_RADIUS_SUCCESS) || - !strlen(hostname) || !strlen(secret)) { - _pam_log(LOG_CRIT, "Could not determine the radius server to talk to"); - return PAM_IGNORE; - } - session_time = time(NULL); - rad_server.hostname = hostname; - rad_server.secret = secret; - retval = radius_acct_start(rad_server, user_name); - if (retval != PWDB_RADIUS_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server"); - return PAM_IGNORE; - } - - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int ctrl; - char *user_name; - int retval; - - ctrl = _pam_parse(argc, argv); - retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); - if ( user_name == NULL || retval != PAM_SUCCESS ) { - _pam_log(LOG_CRIT, "open_session - error recovering username"); - return PAM_SESSION_ERR; - } - - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "closing RADIUS user session for '%s'", - user_name); - - if (!strlen(hostname) || !strlen(secret)) { - _pam_log(LOG_CRIT, "Could not determine the radius server to talk to"); - return PAM_IGNORE; - } - retval = radius_acct_stop(rad_server, user_name, - time(NULL) - session_time); - if (retval != PWDB_RADIUS_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG, "ERROR communicating with the RADIUS server"); - return PAM_IGNORE; - } - - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_radius_modstruct = { - "pam_radius", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL -}; -#endif - -/* - * Copyright (c) Cristian Gafton, 1996, <gafton@redhat.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_radius/pam_radius.h b/modules/pam_radius/pam_radius.h deleted file mode 100644 index 8cee7ff1..00000000 --- a/modules/pam_radius/pam_radius.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * $Id$ - */ - -#ifndef PAM_RADIUS_H -#define PAM_RADIUS_H - -#include <security/_pam_aconf.h> - -#include <stdio.h> - -#ifndef __USE_POSIX2 -#define __USE_POSIX2 -#endif /* __USE_POSIX2 */ - -#include <stdlib.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/resource.h> - -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <syslog.h> -#include <stdarg.h> -#include <utmp.h> -#include <time.h> -#include <netdb.h> - -#include <netinet/in.h> -#include <rpcsvc/ypclnt.h> -#include <rpc/rpc.h> - -#include <pwdb/radius.h> -#include <pwdb/pwdb_radius.h> - -/******************************************************************/ - -#endif /* PAM_RADIUS_H */ diff --git a/modules/pam_rhosts/.cvsignore b/modules/pam_rhosts/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_rhosts/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_rhosts/Makefile b/modules/pam_rhosts/Makefile deleted file mode 100644 index 46d75d6a..00000000 --- a/modules/pam_rhosts/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_rhosts_auth - -include ../Simple.Rules diff --git a/modules/pam_rhosts/README b/modules/pam_rhosts/README deleted file mode 100644 index d2e93d1d..00000000 --- a/modules/pam_rhosts/README +++ /dev/null @@ -1,57 +0,0 @@ -arguments recognized: - -"no_hosts_equiv" -"no_rhosts" -"debug" -"nowarn" -"suppress" -"promiscuous" - -.rhosts/hosts.equiv format: - -There are positive entries, when one is matched authentication -succeeds and terminates. There are negative entries, when one is -matched authentication fails and terminates. Thus order is -significant. - -Entry hosts.equiv .rhosts -<host> All users on <host> are ok Same username from <host> is ok -<host> <user> <user> from <host> is ok ditto --<host> No users from <host> are ok ditto -<host> -<user> <user> from <host> is not ok ditto - -<host> can be ip (IPv4) numbers. - -Netgroups may be used in either host or user fields, and then applies -to all hosts, or users, in the netgroup. The syntax is - - +@<ng> - -The entries - - <host> +@<ng> - +@<ng> +@<ng> - +@<ng> <user> - -means exactly what you think it does. Negative entries are of the -form - - -@<ng> - -When the "promiscuous" option is given the special character + may be -used as a wildcard in any field. - - + Allow anyone from any host to connect. DANGEROUS. - + + Ditto. - + <user> Allow the user to connect from anywhere. DANGEROUS. - <host> + Allow any user from the host. Dangerous. - -These, perhaps more useful, forms of the + form is also disallowed -unless "promiscuous" is specified: - - + -<user> Disallow the user from any host - + -@<ng> Disallow all members of the netgroup from any host - -When "promiscuous" is not specified a '+' is handled as a negative -match. - diff --git a/modules/pam_rhosts/pam_rhosts_auth.c b/modules/pam_rhosts/pam_rhosts_auth.c deleted file mode 100644 index 7266b4e8..00000000 --- a/modules/pam_rhosts/pam_rhosts_auth.c +++ /dev/null @@ -1,795 +0,0 @@ -/*---------------------------------------------------------------------- - * Modified for Linux-PAM by Al Longyear <longyear@netcom.com> 96/5/5 - * Modifications, Cristian Gafton 97/2/8 - * Modifications, Peter Allgeyer 97/3 - * Modifications (netgroups and fixes), Nicolai Langfeldt 97/3/21 - * Security fix: 97/10/2 - gethostbyname called repeatedly without care - * Modification (added privategroup option) Andrew <morgan@transmeta.com> - *---------------------------------------------------------------------- - * Copyright (c) 1983, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <security/_pam_aconf.h> - -#define USER_RHOSTS_FILE "/.rhosts" /* prefixed by user's home dir */ - -#ifdef linux -#include <endian.h> -#endif - -#ifdef HAVE_SYS_FSUID_H -#include <sys/fsuid.h> -#endif /* HAVE_SYS_FSUID_H */ - -#include <sys/types.h> -#include <sys/uio.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> /* This is supposed(?) to contain the following */ -int innetgr(const char *, const char *, const char *,const char *); - -#include <stdio.h> -#include <errno.h> -#include <sys/time.h> -#include <arpa/inet.h> - -#ifndef MAXDNAME -#define MAXDNAME 256 -#endif - -#include <stdarg.h> -#include <ctype.h> - -#include <net/if.h> -#ifdef linux -# include <linux/sockios.h> -# ifndef __USE_MISC -# define __USE_MISC -# include <sys/fsuid.h> -# endif /* __USE_MISC */ -#endif - -#include <pwd.h> -#include <grp.h> -#include <sys/file.h> -#include <sys/signal.h> -#include <sys/stat.h> -#include <syslog.h> -#ifndef _PATH_HEQUIV -#define _PATH_HEQUIV "/etc/hosts.equiv" -#endif /* _PATH_HEQUIV */ - -#define PAM_SM_AUTH /* only defines this management group */ - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> -#include <security/_pam_modutil.h> - -/* to the best of my knowledge, all modern UNIX boxes have 32 bit integers */ -#define U32 unsigned int - - -/* - * Options for this module - */ - -struct _options { - int opt_no_hosts_equiv; - int opt_hosts_equiv_rootok; - int opt_no_rhosts; - int opt_debug; - int opt_nowarn; - int opt_disallow_null_authtok; - int opt_silent; - int opt_promiscuous; - int opt_suppress; - int opt_private_group; - int opt_no_uid_check; - const char *superuser; - const char *last_error; -}; - -/* logging */ -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("pam_rhosts_auth", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -static void set_option (struct _options *opts, const char *arg) -{ - if (strcmp(arg, "no_hosts_equiv") == 0) { - opts->opt_no_hosts_equiv = 1; - return; - } - - if (strcmp(arg, "hosts_equiv_rootok") == 0) { - opts->opt_hosts_equiv_rootok = 1; - return; - } - - if (strcmp(arg, "no_rhosts") == 0) { - opts->opt_no_rhosts = 1; - return; - } - - if (strcmp(arg, "debug") == 0) { - D(("debugging enabled")); - opts->opt_debug = 1; - return; - } - - if (strcmp(arg, "no_warn") == 0) { - opts->opt_nowarn = 1; - return; - } - - if (strcmp(arg, "promiscuous") == 0) { - opts->opt_promiscuous = 1; /* used to permit '+' in ...hosts file */ - return; - } - - if (strcmp(arg, "suppress") == 0) { - opts->opt_suppress = 1; /* used to suppress failure warning message */ - return; - } - - if (strcmp(arg, "privategroup") == 0) { - opts->opt_private_group = 1; /* used to permit group write on .rhosts - file if group has same name as owner */ - return; - } - - if (strcmp(arg, "no_uid_check") == 0) { - opts->opt_no_uid_check = 1; /* NIS optimization */ - return; - } - - if (strcmp(arg, "superuser=") == 0) { - opts->superuser = arg+sizeof("superuser=")-1; - return; - } - /* - * All other options are ignored at the present time. - */ - _pam_log(LOG_WARNING, "unrecognized option '%s'", arg); -} - -static void set_parameters (struct _options *opts, int flags, - int argc, const char **argv) -{ - opts->opt_silent = flags & PAM_SILENT; - opts->opt_disallow_null_authtok = flags & PAM_DISALLOW_NULL_AUTHTOK; - - while (argc-- > 0) { - set_option (opts, *argv); - ++argv; - } -} - -/* - * Obtain the name of the remote host. Currently, this is simply by - * requesting the contents of the PAM_RHOST item. - */ - -static int pam_get_rhost(pam_handle_t *pamh, const char **rhost - , const char *prompt) -{ - int retval; - const char *current; - - retval = pam_get_item (pamh, PAM_RHOST, (const void **)¤t); - if (retval != PAM_SUCCESS) - return retval; - - if (current == NULL) { - return PAM_AUTH_ERR; - } - *rhost = current; - - return retval; /* pass on any error from conversation */ -} - -/* - * Obtain the name of the remote user. Currently, this is simply by - * requesting the contents of the PAM_RUSER item. - */ - -static int pam_get_ruser(pam_handle_t *pamh, const char **ruser, - const char *prompt) -{ - int retval; - const char *current; - - retval = pam_get_item (pamh, PAM_RUSER, (const void **)¤t); - if (retval != PAM_SUCCESS) { - return retval; - } - - if (current == NULL) { - return PAM_AUTH_ERR; - } - *ruser = current; - - return retval; /* pass on any error from conversation */ -} - -/* - * Returns 1 if positive match, 0 if no match, -1 if negative match. - */ - -static int -__icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr - , register char *lhost, const char *rhost) -{ - struct hostent *hp; - U32 laddr; - int negate=1; /* Multiply return with this to get -1 instead of 1 */ - char **pp, *user; - - /* Check nis netgroup. We assume that pam has done all needed - paranoia checking before we are handed the rhost */ - if (strncmp("+@",lhost,2) == 0) - return(innetgr(&lhost[2],rhost,NULL,NULL)); - - if (strncmp("-@",lhost,2) == 0) - return(-innetgr(&lhost[2],rhost,NULL,NULL)); - - /* -host */ - if (strncmp("-",lhost,1) == 0) { - negate=-1; - lhost++; - } else if (strcmp("+",lhost) == 0) { - (void) pam_get_item(pamh, PAM_USER, (const void **)&user); - D(("user %s has a `+' host entry", user)); - if (opts->opt_promiscuous) - return (1); /* asking for trouble, but ok.. */ - /* If not promiscuous: handle as negative */ - return (-1); - } else if (strncmp("+",lhost,1) == 0) { - /* '+hostname' is supposed to be equivalent to 'hostname' */ - lhost++; - } - - - /* Try for raw ip address first. */ - if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) - return (negate*(! (raddr ^ laddr))); - - /* Better be a hostname. */ - hp = gethostbyname(lhost); - if (hp == NULL) - return (0); - - /* Spin through ip addresses. */ - for (pp = hp->h_addr_list; *pp; ++pp) - if (!memcmp (&raddr, *pp, sizeof (U32))) - return (negate); - - /* No match. */ - return (0); -} - -/* Returns 1 on positive match, 0 on no match, -1 on negative match */ - -static int __icheckuser(pam_handle_t *pamh, struct _options *opts - , const char *luser, const char *ruser - , const char *rhost) -{ - /* - luser is user entry from .rhosts/hosts.equiv file - ruser is user id on remote host - rhost is the remote host name - */ - char *user; - - /* [-+]@netgroup */ - if (strncmp("+@",luser,2) == 0) - return (innetgr(&luser[2],NULL,ruser,NULL)); - - if (strncmp("-@",luser,2) == 0) - return (-innetgr(&luser[2],NULL,ruser,NULL)); - - /* -user */ - if (strncmp("-",luser,1) == 0) - return(-(strcmp(&luser[1],ruser) == 0)); - - /* + */ - if (strcmp("+",luser) == 0) { - (void) pam_get_item(pamh, PAM_USER, (const void **)&user); - _pam_log(LOG_WARNING, "user %s has a `+' user entry", user); - if (opts->opt_promiscuous) - return(1); - /* If not promiscuous we handle it as a negative match */ - return(-1); - } - - /* simple string match */ - return (strcmp(ruser, luser) == 0); -} - -/* - * Returns 1 for blank lines (or only comment lines) and 0 otherwise - */ - -static int __isempty(char *p) -{ - while (*p && isspace(*p)) { - ++p; - } - - return (*p == '\0' || *p == '#') ? 1:0 ; -} - -/* - * Returns 0 if positive match, 1 if _not_ ok. - */ - -static int -__ivaliduser (pam_handle_t *pamh, struct _options *opts, - FILE *hostf, U32 raddr, - const char *luser, const char *ruser, const char *rhost) -{ - register const char *user; - register char *p; - int hcheck, ucheck; - char buf[MAXHOSTNAMELEN + 128]; /* host + login */ - - buf[sizeof (buf)-1] = '\0'; /* terminate line */ - - while (fgets(buf, sizeof(buf), hostf) != NULL) { /* hostf file line */ - p = buf; /* from beginning of file.. */ - - /* Skip empty or comment lines */ - if (__isempty(p)) { - continue; - } - - /* Skip lines that are too long. */ - if (strchr(p, '\n') == NULL) { - int ch = getc(hostf); - - while (ch != '\n' && ch != EOF) - ch = getc(hostf); - continue; - } - - /* - * If there is a hostname at the start of the line. Set it to - * lower case. A leading ' ' or '\t' indicates no hostname - */ - - for (;*p && !isspace(*p); ++p) { - *p = tolower(*p); - } - - /* - * next we want to find the permitted name for the remote user - */ - - if (*p == ' ' || *p == '\t') { - - /* <nul> terminate hostname and skip spaces */ - for (*p++='\0'; *p && isspace(*p); ++p); - - user = p; /* this is the user's name */ - while (*p && !isspace(*p)) - ++p; /* find end of user's name */ - } else - user = p; - - *p = '\0'; /* <nul> terminate username (+host?) */ - - /* buf -> host(?) ; user -> username(?) */ - - /* First check host part */ - hcheck=__icheckhost(pamh, opts, raddr, buf, rhost); - - if (hcheck<0) - return(1); - - if (hcheck) { - /* Then check user part */ - if (! (*user)) - user = luser; - - ucheck=__icheckuser(pamh, opts, user, ruser, rhost); - - /* Positive 'host user' match? */ - if (ucheck>0) - return(0); - - /* Negative 'host -user' match? */ - if (ucheck<0) - return(1); - - /* Neither, go on looking for match */ - } - } - - return (1); -} - -/* - * New .rhosts strategy: We are passed an ip address. We spin through - * hosts.equiv and .rhosts looking for a match. When the .rhosts only - * has ip addresses, we don't have to trust a nameserver. When it - * contains hostnames, we spin through the list of addresses the nameserver - * gives us and look for a match. - * - * Returns 0 if ok, -1 if not ok. - */ - -static int -pam_iruserok(pam_handle_t *pamh, - struct _options *opts, U32 raddr, int superuser, - const char *ruser, const char *luser, const char *rhost) -{ - const char *cp; - struct stat sbuf; - struct passwd *pwd; - FILE *hostf; - uid_t uid; - int answer; - char pbuf[MAXPATHLEN]; /* potential buffer overrun */ - - if ((!superuser||opts->opt_hosts_equiv_rootok) && !opts->opt_no_hosts_equiv ) { - - /* try to open system hosts.equiv file */ - hostf = fopen (_PATH_HEQUIV, "r"); - if (hostf) { - answer = __ivaliduser(pamh, opts, hostf, raddr, luser - , ruser, rhost); - (void) fclose(hostf); - if (answer == 0) - return 0; /* remote host is equivalent to localhost */ - } /* else { - No hosts.equiv file on system. - } */ - } - - if ( opts->opt_no_rhosts ) - return 1; - - /* - * Identify user's local .rhosts file - */ - - pwd = _pammodutil_getpwnam(pamh, luser); - if (pwd == NULL) { - /* - * luser is assumed to be valid because of an earlier check for uid = 0 - * we don't log this error twice. However, this shouldn't happen ! - * --cristiang - */ - return(1); - } - - /* check for buffer overrun */ - if (strlen(pwd->pw_dir) + sizeof(USER_RHOSTS_FILE) + 2 >= MAXPATHLEN) { - if (opts->opt_debug) - _pam_log(LOG_DEBUG,"home directory for `%s' is too long", luser); - return 1; /* to dangerous to try */ - } - - (void) strcpy(pbuf, pwd->pw_dir); - (void) strcat(pbuf, USER_RHOSTS_FILE); - - /* - * Change effective uid while _reading_ .rhosts. (not just - * opening). If root and reading an NFS mounted file system, - * can't read files that are 0600 as .rhosts files should be. - */ - - /* We are root, this will not fail */ -#ifdef linux - /* If we are on linux the better way is setfsuid */ - uid = setfsuid(pwd->pw_uid); - hostf = fopen(pbuf, "r"); -#else - uid = geteuid(); - (void) seteuid(pwd->pw_uid); - hostf = fopen(pbuf, "r"); -#endif - - if (hostf == NULL) { - if (opts->opt_debug) - _pam_log(LOG_DEBUG,"Could not open %s file",pbuf); - answer = 1; - goto exit_function; - } - - /* - * If not a regular file, or is owned by someone other than - * user or root or if writeable by anyone but the owner, quit. - */ - - cp = NULL; - if (lstat(pbuf, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)) - cp = ".rhosts not regular file"; - else if (fstat(fileno(hostf), &sbuf) < 0) - cp = ".rhosts fstat failed"; - else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) - cp = "bad .rhosts owner"; - else if (sbuf.st_mode & S_IWOTH) - cp = ".rhosts writable by other!"; - else if (sbuf.st_mode & S_IWGRP) { - - /* private group caveat */ - if (opts->opt_private_group) { - struct group *grp = getgrgid(sbuf.st_gid); - - if (NULL == grp || NULL == grp->gr_name - || strcmp(luser,grp->gr_name)) { - cp = ".rhosts writable by public group"; - } else if (grp->gr_mem) { - int gcount; - - /* require at most one member (luser) of this group */ - for (gcount=0; grp->gr_mem[gcount]; ++gcount) { - if (strcmp(grp->gr_mem[gcount], luser)) { - gcount = -1; - break; - } - } - if (gcount < 0) { - cp = ".rhosts writable by other members of group"; - } - } - } else { - cp = ".rhosts writable by group"; - } - - } /* It is _NOT_ safe to append an else here... Do so prior to - * S_IWGRP check */ - - /* If there were any problems, quit. */ - if (cp) { - opts->last_error = cp; - answer = 1; - goto exit_function; - } - - answer = __ivaliduser (pamh, opts, hostf, raddr, luser, ruser, rhost); - -exit_function: - /* - * Go here to exit after the fsuid/euid has been adjusted so that - * they are reset before we exit. - */ - -#ifdef linux - setfsuid(uid); -#else - (void)seteuid(uid); -#endif - - if (hostf != NULL) - (void) fclose(hostf); - - return answer; -} - -static int -pam_ruserok (pam_handle_t *pamh, - struct _options *opts, const char *rhost, int superuser, - const char *ruser, const char *luser) -{ - struct hostent *hp; - int answer = 1; /* default to failure */ - U32 *addrs; - int n, i; - - opts->last_error = (char *) 0; - hp = gethostbyname(rhost); /* identify host */ - - if (hp != NULL) { - /* First of all check the address length */ - if (hp->h_length != 4) { - _pam_log(LOG_ALERT, "pam_rhosts module can't work with not IPv4 " - "addresses"); - return 1; /* not allowed */ - } - - /* loop though address list */ - for (n = 0; hp->h_addr_list[n]; n++); - D(("rhosts: %d addresses", n)); - - if (n) { - addrs = calloc (n, hp->h_length); - for (i = 0; i < n; i++) - memcpy (addrs+i, hp->h_addr_list[i], hp->h_length); - - for (i = 0; i < n && answer; i++) { - D(("rhosts: address %d is %04x", i, addrs[i])); - answer = pam_iruserok(pamh, opts, addrs[i], superuser, - ruser, luser, rhost); - /* answer == 0 means success */ - } - - free (addrs); - } - } - - return answer; -} - -/* - * Internal function to do authentication - */ - -static int _pam_auth_rhosts (pam_handle_t *pamh, - int flags, - int argc, - const char **argv) -{ - int retval; - const char *luser = NULL; - const char *ruser = NULL, *rhost = NULL; - struct _options opts; - int as_root = 0; - - /* - * Look at the options and set the flags accordingly. - */ - memset (&opts, 0, sizeof (opts)); - set_parameters (&opts, flags, argc, argv); - /* - * Obtain the parameters for the various items - */ - for (;;) { /* abuse loop to avoid goto */ - - /* get the remotehost */ - D(("getting rhost")); - retval = pam_get_rhost(pamh, &rhost, NULL); - (void) pam_set_item(pamh, PAM_RHOST, rhost); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) { - _pam_log(LOG_DEBUG, "could not get the remote host name"); - } - break; - } - - /* get the remote user */ - D(("getting ruser")); - retval = pam_get_ruser(pamh, &ruser, NULL); - (void) pam_set_item(pamh, PAM_RUSER, ruser); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) - _pam_log(LOG_DEBUG, "could not get the remote username"); - break; - } - - /* get the local user */ - D(("getting user")); - retval = pam_get_user(pamh, &luser, NULL); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) - _pam_log(LOG_DEBUG, "could not determine name of local user"); - break; - } - - if (opts.superuser && !strcmp(opts.superuser, luser)) { - as_root = 1; - } - - /* check if the luser uid == 0... --cristiang */ - if (! opts.opt_no_uid_check) { - struct passwd *luser_pwd; - - luser_pwd = _pammodutil_getpwnam(pamh, luser); - if (luser_pwd == NULL) { - if (opts.opt_debug) - _pam_log(LOG_DEBUG, "user '%s' unknown to this system", - luser); - retval = PAM_AUTH_ERR; - break; - } - if (luser_pwd->pw_uid == 0) - as_root = 1; - luser_pwd = NULL; /* forget */ - } -/* - * Validate the account information. - */ - if (pam_ruserok (pamh, &opts, rhost, as_root, ruser, luser) != 0) { - if ( !opts.opt_suppress ) { - _pam_log(LOG_WARNING, "denied to %s@%s as %s: %s", - ruser, rhost, luser, (opts.last_error==NULL) ? - "access not allowed":opts.last_error); - } - retval = PAM_AUTH_ERR; - } else { - _pam_log(LOG_NOTICE, "allowed to %s@%s as %s", - ruser, rhost, luser); - } - break; - } - - return retval; -} - -/* --- authentication management functions --- */ - -PAM_EXTERN -int pam_sm_authenticate (pam_handle_t *pamh, - int flags, - int argc, - const char **argv) -{ - int retval; - - if (sizeof(U32) != 4) { - _pam_log (LOG_ALERT, "pam_rhosts module can\'t work on this hardware " - "(yet)"); - return PAM_AUTH_ERR; - } - sethostent(1); - retval = _pam_auth_rhosts (pamh, flags, argc, argv); - endhostent(); - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc, - const char **argv) -{ - return PAM_SUCCESS; -} - -/* end of module definition */ - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_rhosts_auth_modstruct = { - "pam_rhosts_auth", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif diff --git a/modules/pam_rootok/.cvsignore b/modules/pam_rootok/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_rootok/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_rootok/Makefile b/modules/pam_rootok/Makefile deleted file mode 100644 index 3460c2a2..00000000 --- a/modules/pam_rootok/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_rootok - -include ../Simple.Rules diff --git a/modules/pam_rootok/README b/modules/pam_rootok/README deleted file mode 100644 index cccb5ce1..00000000 --- a/modules/pam_rootok/README +++ /dev/null @@ -1,18 +0,0 @@ -# $Id$ -# - -this module is an authentication module that performs one task: if the -id of the user is '0' then it returns 'PAM_SUCCESS' with the -'sufficient' /etc/pam.conf control flag it can be used to allow -password free access to some service for 'root' - -Recognized arguments: - - debug write a message to syslog indicating success or - failure. - -module services provided: - - auth _authentication and _setcred (blank) - -Andrew Morgan diff --git a/modules/pam_rootok/pam_rootok.c b/modules/pam_rootok/pam_rootok.c deleted file mode 100644 index a7342104..00000000 --- a/modules/pam_rootok/pam_rootok.c +++ /dev/null @@ -1,110 +0,0 @@ -/* pam_rootok module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <unistd.h> -#include <syslog.h> -#include <stdarg.h> -#include <string.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-rootok", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - - -/* argument parsing */ - -#define PAM_DEBUG_ARG 01 - -static int _pam_parse(int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int ctrl; - int retval = PAM_AUTH_ERR; - - ctrl = _pam_parse(argc, argv); - if (getuid() == 0) - retval = PAM_SUCCESS; - - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_DEBUG, "authentication %s" - , retval==PAM_SUCCESS ? "succeeded":"failed" ); - } - - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_rootok_modstruct = { - "pam_rootok", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_securetty/.cvsignore b/modules/pam_securetty/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_securetty/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_securetty/Makefile b/modules/pam_securetty/Makefile deleted file mode 100644 index 9b80d2e9..00000000 --- a/modules/pam_securetty/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_securetty - -include ../Simple.Rules diff --git a/modules/pam_securetty/README b/modules/pam_securetty/README deleted file mode 100644 index 1df095c9..00000000 --- a/modules/pam_securetty/README +++ /dev/null @@ -1,9 +0,0 @@ -pam_securetty: - Allows root logins only if the user is logging in on a - "secure" tty, as defined by the listing in /etc/securetty - - Also checks to make sure that /etc/securetty is a plain - file and not world writable. - - - Elliot Lee <sopwith@redhat.com>, Red Hat Software. - July 25, 1996. diff --git a/modules/pam_securetty/pam_securetty.c b/modules/pam_securetty/pam_securetty.c deleted file mode 100644 index 9e6121e8..00000000 --- a/modules/pam_securetty/pam_securetty.c +++ /dev/null @@ -1,191 +0,0 @@ -/* pam_securetty module */ - -#define SECURETTY_FILE "/etc/securetty" -#define TTY_PREFIX "/dev/" - -/* - * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. - * July 25, 1996. - * This code shamelessly ripped from the pam_rootok module. - * Slight modifications AGM. 1996/12/3 - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <syslog.h> -#include <stdarg.h> -#include <pwd.h> -#include <string.h> - -#define PAM_SM_AUTH - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-securetty", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 - -static int _pam_parse(int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int retval = PAM_AUTH_ERR; - const char *username; - char *uttyname; - char ttyfileline[256]; - struct stat ttyfileinfo; - struct passwd *user_pwd; - FILE *ttyfile; - int ctrl; - - /* parse the arguments */ - ctrl = _pam_parse(argc, argv); - - retval = pam_get_user(pamh, &username, NULL); - if (retval != PAM_SUCCESS || username == NULL) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_WARNING, "cannot determine username"); - } - return (retval == PAM_CONV_AGAIN - ? PAM_INCOMPLETE:PAM_SERVICE_ERR); - } - - retval = pam_get_item(pamh, PAM_TTY, (const void **)&uttyname); - if (retval != PAM_SUCCESS || uttyname == NULL) { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_WARNING, "cannot determine user's tty"); - } - return PAM_SERVICE_ERR; - } - - /* The PAM_TTY item may be prefixed with "/dev/" - skip that */ - if (strncmp(TTY_PREFIX, uttyname, sizeof(TTY_PREFIX)-1) == 0) - uttyname += sizeof(TTY_PREFIX)-1; - - user_pwd = getpwnam(username); - if (user_pwd == NULL) { - return PAM_IGNORE; - } else if (user_pwd->pw_uid != 0) { /* If the user is not root, - securetty's does not apply - to them */ - return PAM_SUCCESS; - } - - if (stat(SECURETTY_FILE, &ttyfileinfo)) { - _pam_log(LOG_NOTICE, "Couldn't open " SECURETTY_FILE); - return PAM_SUCCESS; /* for compatibility with old securetty handling, - this needs to succeed. But we still log the - error. */ - } - - if ((ttyfileinfo.st_mode & S_IWOTH) - || !S_ISREG(ttyfileinfo.st_mode)) { - /* If the file is world writable or is not a - normal file, return error */ - _pam_log(LOG_ERR, SECURETTY_FILE - " is either world writable or not a normal file"); - return PAM_AUTH_ERR; - } - - ttyfile = fopen(SECURETTY_FILE,"r"); - if(ttyfile == NULL) { /* Check that we opened it successfully */ - _pam_log(LOG_ERR, - "Error opening " SECURETTY_FILE); - return PAM_SERVICE_ERR; - } - /* There should be no more errors from here on */ - retval=PAM_AUTH_ERR; - /* This loop assumes that PAM_SUCCESS == 0 - and PAM_AUTH_ERR != 0 */ - while((fgets(ttyfileline,sizeof(ttyfileline)-1, ttyfile) != NULL) - && retval) { - if(ttyfileline[strlen(ttyfileline) - 1] == '\n') - ttyfileline[strlen(ttyfileline) - 1] = '\0'; - retval = strcmp(ttyfileline,uttyname); - } - fclose(ttyfile); - if(retval) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_WARNING, "access denied: tty '%s' is not secure !", - uttyname); - retval = PAM_AUTH_ERR; - } - if ((retval == PAM_SUCCESS) && (ctrl & PAM_DEBUG_ARG)) - _pam_log(LOG_DEBUG, "access allowed for '%s' on '%s'", - username, uttyname); - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_securetty_modstruct = { - "pam_securetty", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_shells/.cvsignore b/modules/pam_shells/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_shells/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_shells/Makefile b/modules/pam_shells/Makefile deleted file mode 100644 index b057dc00..00000000 --- a/modules/pam_shells/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_shells - -include ../Simple.Rules diff --git a/modules/pam_shells/README b/modules/pam_shells/README deleted file mode 100644 index cbd5bfb5..00000000 --- a/modules/pam_shells/README +++ /dev/null @@ -1,10 +0,0 @@ -pam_shells: - Authentication is granted if the users shell is listed in - /etc/shells. If no shell is in /etc/passwd (empty), the - /bin/sh is used (following ftpd's convention). - - Also checks to make sure that /etc/shells is a plain - file and not world writable. - - - Erik Troan <ewt@redhat.com>, Red Hat Software. - August 5, 1996. diff --git a/modules/pam_shells/pam_shells.c b/modules/pam_shells/pam_shells.c deleted file mode 100644 index 36dd1a91..00000000 --- a/modules/pam_shells/pam_shells.c +++ /dev/null @@ -1,133 +0,0 @@ -/* pam_shells module */ - -#define SHELL_FILE "/etc/shells" - -/* - * by Erik Troan <ewt@redhat.com>, Red Hat Software. - * August 5, 1996. - * This code shamelessly ripped from the pam_securetty module. - */ - -#define _BSD_SOURCE - -#include <pwd.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <syslog.h> -#include <unistd.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-shells", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int retval = PAM_AUTH_ERR; - const char *userName; - char *userShell; - char shellFileLine[256]; - struct stat sb; - struct passwd * pw; - FILE * shellFile; - - retval = pam_get_user(pamh,&userName,NULL); - if(retval != PAM_SUCCESS) - return PAM_SERVICE_ERR; - - if(!userName || (strlen(userName) <= 0)) { - /* Don't let them use a NULL username... */ - pam_get_user(pamh,&userName,NULL); - if (retval != PAM_SUCCESS) - return PAM_SERVICE_ERR; - } - - pw = getpwnam(userName); - if (!pw) - return PAM_AUTH_ERR; /* user doesn't exist */ - userShell = pw->pw_shell; - - if(stat(SHELL_FILE,&sb)) { - _pam_log(LOG_ERR, - "%s cannot be stat'd (it probably does not exist)", SHELL_FILE); - return PAM_AUTH_ERR; /* must have /etc/shells */ - } - - if((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { - _pam_log(LOG_ERR, - "%s is either world writable or not a normal file", SHELL_FILE); - return PAM_AUTH_ERR; - } - - shellFile = fopen(SHELL_FILE,"r"); - if(shellFile == NULL) { /* Check that we opened it successfully */ - _pam_log(LOG_ERR, - "Error opening %s", SHELL_FILE); - return PAM_SERVICE_ERR; - } - /* There should be no more errors from here on */ - retval=PAM_AUTH_ERR; - /* This loop assumes that PAM_SUCCESS == 0 - and PAM_AUTH_ERR != 0 */ - while((fgets(shellFileLine,255,shellFile) != NULL) - && retval) { - if (shellFileLine[strlen(shellFileLine) - 1] == '\n') - shellFileLine[strlen(shellFileLine) - 1] = '\0'; - retval = strcmp(shellFileLine, userShell); - } - fclose(shellFile); - if(retval) - retval = PAM_AUTH_ERR; - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_shells_modstruct = { - "pam_shells", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_stress/.cvsignore b/modules/pam_stress/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_stress/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_stress/Makefile b/modules/pam_stress/Makefile deleted file mode 100644 index 598809a5..00000000 --- a/modules/pam_stress/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_stress - -include ../Simple.Rules diff --git a/modules/pam_stress/README b/modules/pam_stress/README deleted file mode 100644 index 74a297b2..00000000 --- a/modules/pam_stress/README +++ /dev/null @@ -1,66 +0,0 @@ -# -# $Id$ -# -# This describes the behavior of this module with respect to the -# /etc/pam.conf file. -# -# writen by Andrew Morgan <morgan@parc.power.net> -# - -This module recognizes the following arguments. - -debug put lots of information in syslog. - *NOTE* this option writes passwords to syslog, so - don't use anything sensitive when testing. - -no_warn don't give warnings about things (otherwise warnings are issued - via the conversation function) - -use_first_pass don't prompt for a password, for pam_sm_authentication - function just use item PAM_AUTHTOK. - -try_first_pass don't prompt for a password unless there has been no - previous authentication token (item PAM_AUTHTOK is NULL) - -rootok This is intended for the pam_sm_chauthtok function and - it instructs this function to permit root to change - the user's password without entering the old password. - -The following arguments are acted on by the module. They are intended -to make the module give the impression of failing as a fully -functioning module might. - -expired an argument intended for the account and chauthtok module - parts. It instructs the module to act as if the user's - password has expired - -fail_1 this instructs the module to make its first function fail. - -fail_2 this instructs the module to make its second function (if there - is one) fail. - - The function break up is indicated in the Module - Developers' Guide. Listed here it is: - - service function 1 function 2 - ------- ---------- ---------- - auth pam_sm_authenticate pam_sm_setcred - password pam_sm_chauthtok - session pam_sm_open_session pam_sm_close_session - account pam_sm_acct_mgmt - -prelim for pam_sm_chauthtok, means fail on PAM_PRELIM_CHECK. - -required for pam_sm_chauthtok, means fail if the user hasn't already - been authenticated by this module. (See stress_new_pwd data - item below.) - -# -# data strings that this module uses are the following: -# - -data name value(s) Comments ---------- -------- -------- -stress_new_pwd yes tells pam_sm_chauthtok that - pam_sm_acct_mgmt says we need a new - password diff --git a/modules/pam_stress/pam_stress.c b/modules/pam_stress/pam_stress.c deleted file mode 100644 index f5126fd2..00000000 --- a/modules/pam_stress/pam_stress.c +++ /dev/null @@ -1,565 +0,0 @@ -/* pam_stress module */ - -/* $Id$ - * - * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12 - */ - -#include <security/_pam_aconf.h> - -#include <stdlib.h> -#include <stdio.h> - -#define __USE_BSD -#include <syslog.h> - -#include <stdarg.h> -#include <string.h> -#include <unistd.h> - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -static char *_strdup(const char *x) -{ - char *new; - new = malloc(strlen(x)+1); - strcpy(new,x); - return new; -} - -/* log errors */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* ---------- */ - -/* an internal function to turn all possible test arguments into bits - of a ctrl number */ - -/* generic options */ - -#define PAM_ST_DEBUG 01 -#define PAM_ST_NO_WARN 02 -#define PAM_ST_USE_PASS1 04 -#define PAM_ST_TRY_PASS1 010 -#define PAM_ST_ROOTOK 020 - -/* simulation options */ - -#define PAM_ST_EXPIRED 040 -#define PAM_ST_FAIL_1 0100 -#define PAM_ST_FAIL_2 0200 -#define PAM_ST_PRELIM 0400 -#define PAM_ST_REQUIRE_PWD 01000 - -/* some syslogging */ - -static void _pam_report(int ctrl, const char *name, int flags, - int argc, const char **argv) -{ - if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG, "CALLED: %s", name); - _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags, - (flags & PAM_SILENT) ? " (silent)":""); - _pam_log(LOG_DEBUG, "CTRL = 0%o",ctrl); - _pam_log(LOG_DEBUG, "ARGV :"); - while (argc--) { - _pam_log(LOG_DEBUG, " \"%s\"", *argv++); - } - } -} - -static int _pam_parse(int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_ST_DEBUG; - else if (!strcmp(*argv,"no_warn")) - ctrl |= PAM_ST_NO_WARN; - else if (!strcmp(*argv,"use_first_pass")) - ctrl |= PAM_ST_USE_PASS1; - else if (!strcmp(*argv,"try_first_pass")) - ctrl |= PAM_ST_TRY_PASS1; - else if (!strcmp(*argv,"rootok")) - ctrl |= PAM_ST_ROOTOK; - - /* simulation options */ - - else if (!strcmp(*argv,"expired")) /* signal password needs - renewal */ - ctrl |= PAM_ST_EXPIRED; - else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */ - ctrl |= PAM_ST_FAIL_1; - else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */ - ctrl |= PAM_ST_FAIL_2; - else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred - to fail on first call */ - ctrl |= PAM_ST_PRELIM; - else if (!strcmp(*argv,"required")) /* module is fussy about the - user being authenticated */ - ctrl |= PAM_ST_REQUIRE_PWD; - - else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -static int converse(pam_handle_t *pamh, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv)) - == PAM_SUCCESS) { - retval = conv->conv(nargs, (const struct pam_message **) message - , response, conv->appdata_ptr); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval); - _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval)); - } - } else { - _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv"); - } - - return retval; -} - -/* authentication management functions */ - -static int stress_get_password(pam_handle_t *pamh, int flags - , int ctrl, char **password) -{ - char *pass; - - if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1)) - && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass) - == PAM_SUCCESS) - && (pass != NULL) ) { - pass = _strdup(pass); - } else if ((ctrl & PAM_ST_USE_PASS1)) { - _pam_log(LOG_WARNING, "pam_stress: no forwarded password"); - return PAM_PERM_DENIED; - } else { /* we will have to get one */ - struct pam_message msg[1],*pmsg[1]; - struct pam_response *resp; - int retval; - - /* set up conversation call */ - - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_PROMPT_ECHO_OFF; - msg[0].msg = "STRESS Password: "; - resp = NULL; - - if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) { - return retval; - } - - if (resp) { - if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) { - _pam_log(LOG_DEBUG, - "pam_sm_authenticate: NULL authtok given"); - } - if ((flags & PAM_DISALLOW_NULL_AUTHTOK) - && resp[0].resp == NULL) { - free(resp); - return PAM_AUTH_ERR; - } - - pass = resp[0].resp; /* remember this! */ - - resp[0].resp = NULL; - } else if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported"); - _pam_log(LOG_DEBUG,"getting password, but NULL returned!?"); - return PAM_CONV_ERR; - } - free(resp); - } - - *password = pass; /* this *MUST* be free()'d by this module */ - - return PAM_SUCCESS; -} - -/* function to clean up data items */ - -static void wipe_up(pam_handle_t *pamh, void *data, int error) -{ - free(data); -} - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - const char *username; - int retval=PAM_SUCCESS; - char *pass; - int ctrl; - - D(("called.")); - - ctrl = _pam_parse(argc,argv); - _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv); - - /* try to get the username */ - - retval = pam_get_user(pamh, &username, "username: "); - if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) { - _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username); - } else if (retval != PAM_SUCCESS) { - _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username"); - return retval; - } - - /* now get the password */ - - retval = stress_get_password(pamh,flags,ctrl,&pass); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_WARNING, "pam_sm_authenticate: " - "failed to get a password"); - return retval; - } - - /* try to set password item */ - - retval = pam_set_item(pamh,PAM_AUTHTOK,pass); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_WARNING, "pam_sm_authenticate: " - "failed to store new password"); - _pam_overwrite(pass); - free(pass); - return retval; - } - - /* clean up local copy of password */ - - _pam_overwrite(pass); - free(pass); - pass = NULL; - - /* if we are debugging then we print the password */ - - if (ctrl & PAM_ST_DEBUG) { - (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass); - _pam_log(LOG_DEBUG, - "pam_st_authenticate: password entered is: [%s]\n",pass); - pass = NULL; - } - - /* if we signal a fail for this function then fail */ - - if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS) - return PAM_PERM_DENIED; - - return retval; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int ctrl = _pam_parse(argc,argv); - - D(("called. [post parsing]")); - - _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv); - - if (ctrl & PAM_ST_FAIL_2) - return PAM_CRED_ERR; - - return PAM_SUCCESS; -} - -/* account management functions */ - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int ctrl = _pam_parse(argc,argv); - - D(("called. [post parsing]")); - - _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv); - - if (ctrl & PAM_ST_FAIL_1) - return PAM_PERM_DENIED; - else if (ctrl & PAM_ST_EXPIRED) { - void *text = malloc(sizeof("yes")+1); - strcpy(text,"yes"); - pam_set_data(pamh,"stress_new_pwd",text,wipe_up); - if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password"); - } - return PAM_NEW_AUTHTOK_REQD; - } - - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - char *username,*service; - int ctrl = _pam_parse(argc,argv); - - D(("called. [post parsing]")); - - _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv); - - if ((pam_get_item(pamh, PAM_USER, (const void **) &username) - != PAM_SUCCESS) - || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service) - != PAM_SUCCESS)) { - _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?"); - return PAM_SESSION_ERR; - } - - _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]" - , service, username); - - if (ctrl & PAM_ST_FAIL_1) - return PAM_SESSION_ERR; - - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - const char *username,*service; - int ctrl = _pam_parse(argc,argv); - - D(("called. [post parsing]")); - - _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv); - - if ((pam_get_item(pamh, PAM_USER, (const void **)&username) - != PAM_SUCCESS) - || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) - != PAM_SUCCESS)) { - _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?"); - return PAM_SESSION_ERR; - } - - _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]" - , service, username); - - if (ctrl & PAM_ST_FAIL_2) - return PAM_SESSION_ERR; - - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval; - int ctrl = _pam_parse(argc,argv); - - D(("called. [post parsing]")); - - _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv); - - /* this function should be called twice by the Linux-PAM library */ - - if (flags & PAM_PRELIM_CHECK) { /* first call */ - if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check"); - } - if (ctrl & PAM_ST_PRELIM) - return PAM_TRY_AGAIN; - - return PAM_SUCCESS; - } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */ - struct pam_message msg[3],*pmsg[3]; - struct pam_response *resp; - const char *text; - char *txt=NULL; - int i; - - if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password"); - } - - if (ctrl & PAM_ST_FAIL_1) - return PAM_AUTHTOK_LOCK_BUSY; - - if ( !(ctrl && PAM_ST_EXPIRED) - && (flags & PAM_CHANGE_EXPIRED_AUTHTOK) - && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text) - != PAM_SUCCESS || strcmp(text,"yes"))) { - return PAM_SUCCESS; /* the token has not expired */ - } - - /* the password should be changed */ - - if ((ctrl & PAM_ST_REQUIRE_PWD) - && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK)) - ) { /* first get old one? */ - char *pass; - - if (ctrl & PAM_ST_DEBUG) { - _pam_log(LOG_DEBUG - ,"pam_sm_chauthtok: getting old password"); - } - retval = stress_get_password(pamh,flags,ctrl,&pass); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_DEBUG - ,"pam_sm_chauthtok: no password obtained"); - return retval; - } - retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_DEBUG - ,"pam_sm_chauthtok: could not set OLDAUTHTOK"); - _pam_overwrite(pass); - free(pass); - return retval; - } - _pam_overwrite(pass); - free(pass); - } - - /* set up for conversation */ - - if (!(flags & PAM_SILENT)) { - char *username; - - if ( pam_get_item(pamh, PAM_USER, (const void **)&username) - || username == NULL ) { - _pam_log(LOG_ERR,"no username set"); - return PAM_USER_UNKNOWN; - } - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; -#define _LOCAL_STRESS_COMMENT "Changing STRESS password for " - txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT) - +strlen(username)+1); - strcpy(txt, _LOCAL_STRESS_COMMENT); -#undef _LOCAL_STRESS_COMMENT - strcat(txt, username); - msg[0].msg = txt; - i = 1; - } else { - i = 0; - } - - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = "Enter new STRESS password: "; - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = "Retype new STRESS password: "; - resp = NULL; - - retval = converse(pamh,i,pmsg,&resp); - if (txt) { - free(txt); - txt = NULL; /* clean up */ - } - if (retval != PAM_SUCCESS) { - return retval; - } - - if (resp == NULL) { - _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv"); - return PAM_CONV_ERR; - } - - /* store the password */ - - if (resp[i-2].resp && resp[i-1].resp) { - if (strcmp(resp[i-2].resp,resp[i-1].resp)) { - /* passwords are not the same; forget and return error */ - - _pam_drop_reply(resp, i); - - if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) { - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_ERROR_MSG; - msg[0].msg = "Verification mis-typed; " - "password unchaged"; - resp = NULL; - (void) converse(pamh,1,pmsg,&resp); - if (resp) { - _pam_drop_reply(resp, 1); - } - } - return PAM_AUTHTOK_ERR; - } - - if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text) - == PAM_SUCCESS) { - (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text); - text = NULL; - } - (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp); - } else { - _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp"); - retval = PAM_SYSTEM_ERR; - } - - _pam_drop_reply(resp, i); /* clean up the passwords */ - } else { - _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error"); - return PAM_SYSTEM_ERR; - } - - return retval; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_stress_modstruct = { - "pam_stress", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok -}; - -#endif diff --git a/modules/pam_tally/.cvsignore b/modules/pam_tally/.cvsignore deleted file mode 100644 index e1a4f48f..00000000 --- a/modules/pam_tally/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -dynamic -pam_tally diff --git a/modules/pam_tally/Makefile b/modules/pam_tally/Makefile deleted file mode 100644 index 1c5106e3..00000000 --- a/modules/pam_tally/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module and -# application for Linux-PAM. You should not modify this Makefile -# (unless you know what you are doing!). -# -# - -include ../../Make.Rules - -TITLE=pam_tally - -# -## Additional rules for making (and moving) the application added. -## Assuming that all modules' applications are called $TITLE -# - -LIBSRC = $(TITLE).c -LIBOBJ = $(TITLE).o -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -LIBOBJS = $(addprefix static/,$(LIBOBJ)) - -APPSRC = $(TITLE)_app.c -APPOBJ = $(TITLE)_app.o -APPOBJD = $(addprefix dynamic/,$(APPOBJ)) -APPOBJS = $(addprefix static/,$(APPOBJ)) - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o : %.c - $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - - -ifdef DYNAMIC -LIBSHARED = $(TITLE).so -endif - -ifdef STATIC -LIBSTATIC = lib$(TITLE).o -endif - -APPLICATION = $(TITLE) -APPMODE = 755 - -####################### don't edit below ####################### - -all: dirs $(LIBSHARED) $(LIBSTATIC) register $(APPLICATION) - -dirs: -ifdef DYNAMIC - $(MKDIR) ./dynamic -endif -ifdef STATIC - $(MKDIR) ./static -endif - -register: -ifdef STATIC - ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) ) -endif - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) - -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) - -$(APPLICATION): $(APPOBJD) $(TITLE).c - $(CC) $(CFLAGS) -o $@ $(APPOBJD) $(LOADLIBES) - -endif - -ifdef STATIC -$(LIBOBJS): $(LIBSRC) - -$(LIBSTATIC): $(LIBOBJS) - $(LD) -r -o $@ $(LIBOBJS) - -$(APPLICATION): $(APPOBJS) $(TITLE).c - $(CC) $(CFLAGS) -o $@ $(APPOBJS) $(LOADLIBES) -endif - -install: all - $(MKDIR) $(FAKEROOT)$(SECUREDIR) -ifdef DYNAMIC - $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) -endif - $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) - $(INSTALL) -m $(APPMODE) $(APPLICATION) $(FAKEROOT)$(SUPLEMENTED) - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so - rm -f $(FAKEROOT)$(SUPLEMENTED)/$(TITLE) - -clean: - rm -f $(LIBOBJD) $(LIBOBJS) $(APPOBJD) $(APPOBJS) core *~ - rm -f *.a *.o *.so *.bak dynamic/* static/* $(APPLICATION) - rm -rf dynamic static - -.c.o: - $(CC) $(CFLAGS) -c $< diff --git a/modules/pam_tally/README b/modules/pam_tally/README deleted file mode 100644 index 4c421648..00000000 --- a/modules/pam_tally/README +++ /dev/null @@ -1,95 +0,0 @@ -SUMMARY: - pam_tally: - - Maintains a count of attempted accesses, can reset count on success, - can deny access if too many attempts fail. - - Options: - - * onerr=[succeed|fail] (if something weird happens - such as unable to open the file, what to do?) - * file=/where/to/keep/counts (default /var/log/faillog) - - (auth) - Authentication phase increments attempted login counter. - * no_magic_root (root DOES increment counter. Use for - daemon-based stuff, like telnet/rsh/login) - - (account) - Account phase can deny access and/or reset attempts counter. - * deny=n (deny access if tally for this user exceeds n; - The presence of deny=n changes the default for - reset/no_reset to reset, unless the user trying to - gain access is root and the no_magic_root option - has NOT been specified.) - - * no_magic_root (access attempts by root DON'T ignore deny. - Use this for daemon-based stuff, like telnet/rsh/login) - * even_deny_root_account (Root can become unavailable. BEWARE. - Note that magic root trying to gain root bypasses this, - but normal users can be locked out.) - - * reset (reset count to 0 on successful entry, even for - magic root) - * no_reset (don't reset count on successful entry) - This is the default unless deny exists and the - user attempting access is NOT magic root. - - * per_user (If /var/log/faillog contains a non-zero - .fail_max field for this user then use it - instead of deny=n parameter) - - * no_lock_time (Don't use .fail_locktime filed in - /var/log/faillog for this user) - - Also checks to make sure that the counts file is a plain - file and not world writable. - - - Tim Baverstock <warwick@sable.demon.co.uk>, v0.1 5 March 1997 - -LONGER: - -pam_tally comes in two parts: pam_tally.so and pam_tally. - -pam_tally.so sits in a pam config file, in the auth and account sections. - -In the auth section, it increments a per-uid counter for each attempted -login, in the account section, it denies access if attempted logins -exceed some threashold and/or resets that counter to zero on successful -login. - -Root is treated specially: - -1. When a process already running as root tries to access some service, the -access is `magic', and bypasses pam_tally's checks: handy for `su'ing from -root into an account otherwise blocked. However, for services like telnet or -login which always effectively run from the root account, root (ie everyone) -shouldn't be granted this magic status, and the flag `no_magic_root' should -be set in this situation, as noted in the summary above. [This option may -be obsolete, with `sufficient root' processing.] - -2. Normally, failed attempts to access root will NOT cause the root -account to become blocked, to prevent denial-of-service: if your users aren't -given shell accounts and root may only login via `su' or at the machine -console (not telnet/rsh, etc), this is safe. If you really want root to be -blocked for some given service, use even_deny_root_account. - -pam_tally is an (optional) application which can be used to interrogate and -manipulate the counter file. It can display users' counts, set individual -counts, or clear all counts. Setting artificially high counts may be useful -for blocking users without changing their passwords. I found it useful to -clear all counts every midnight from a cron.. - -The counts file is organised as a binary-word array, indexed by uid. You -can probably make sense of it with `od', if you don't want to use the -supplied application. - -BUGS: - -pam_tally is very dependant on getpw*(): a database of usernames -would be much more flexible. - -The (4.0 Redhat) utilities seem to do funny things with uid, and I'm -not wholly sure I understood what I should have been doing anyway so -the `keep a count of current logins' bit has been #ifdef'd out and you -can only reset the counter on successful authentication, for now. diff --git a/modules/pam_tally/faillog.h b/modules/pam_tally/faillog.h deleted file mode 100644 index 7f704713..00000000 --- a/modules/pam_tally/faillog.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 1989 - 1994, Julianne Frances Haugh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Julianne F. Haugh nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * faillog.h - login failure logging file format - * - * $Id$ - * - * The login failure file is maintained by login(1) and faillog(8) - * Each record in the file represents a separate UID and the file - * is indexed in that fashion. - */ - -#ifndef _FAILLOG_H -#define _FAILLOG_H - -struct faillog { - short fail_cnt; /* failures since last success */ - short fail_max; /* failures before turning account off */ - char fail_line[12]; /* last failure occured here */ - time_t fail_time; /* last failure occured then */ - /* - * If nonzero, the account will be re-enabled if there are no - * failures for fail_locktime seconds since last failure. - */ - long fail_locktime; -}; - -#endif diff --git a/modules/pam_tally/pam_tally.c b/modules/pam_tally/pam_tally.c deleted file mode 100644 index 3da37f40..00000000 --- a/modules/pam_tally/pam_tally.c +++ /dev/null @@ -1,735 +0,0 @@ -/* - * pam_tally.c - * - * $Id$ - */ - - -/* By Tim Baverstock <warwick@mmm.co.uk>, Multi Media Machine Ltd. - * 5 March 1997 - * - * Stuff stolen from pam_rootok and pam_listfile - */ - -#include <security/_pam_aconf.h> - -#if defined(MAIN) && defined(MEMORY_DEBUG) -# undef exit -#endif /* defined(MAIN) && defined(MEMORY_DEBUG) */ - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <stdlib.h> -#include <syslog.h> -#include <pwd.h> -#include <time.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include "faillog.h" - -#ifndef TRUE -#define TRUE 1L -#define FALSE 0L -#endif - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -/* #define PAM_SM_SESSION */ -/* #define PAM_SM_PASSWORD */ - -#include <security/pam_modules.h> - -/*---------------------------------------------------------------------*/ - -#define DEFAULT_LOGFILE "/var/log/faillog" -#define MODULE_NAME "pam_tally" - -enum TALLY_RESET { - TALLY_RESET_DEFAULT, - TALLY_RESET_RESET, - TALLY_RESET_NO_RESET -}; - -#define tally_t unsigned short int -#define TALLY_FMT "%hu" -#define TALLY_HI ((tally_t)~0L) - -#define UID_FMT "%hu" - -#ifndef FILENAME_MAX -# define FILENAME_MAX MAXPATHLEN -#endif - -struct fail_s { - struct faillog fs_faillog; -#ifndef MAIN - time_t fs_fail_time; -#endif /* ndef MAIN */ -}; - -/*---------------------------------------------------------------------*/ - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - va_start(args, format); - -#ifdef MAIN - vfprintf(stderr,format,args); - fprintf(stderr,"\n"); -#else - openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - closelog(); -#endif - va_end(args); -} - -/*---------------------------------------------------------------------*/ - -/* --- Support function: get uid (and optionally username) from PAM or - cline_user --- */ - -#ifdef MAIN -static char *cline_user=0; /* cline_user is used in the administration prog */ -#endif - -static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) - { - const char *user; - struct passwd *pw; - -#ifdef MAIN - user = cline_user; -#else - pam_get_user( pamh, &user, NULL ); -#endif - - if ( !user || !*user ) { - _pam_log(LOG_ERR, MODULE_NAME ": pam_get_uid; user?"); - return PAM_AUTH_ERR; - } - - if ( ! ( pw = getpwnam( user ) ) ) { - _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user %s",user); - return PAM_USER_UNKNOWN; - } - - if ( uid ) *uid = pw->pw_uid; - if ( userp ) *userp = user; - return PAM_SUCCESS; - } - -/*---------------------------------------------------------------------*/ - -/* --- Support function: open/create tallyfile and return tally for uid --- */ - -/* If on entry *tally==TALLY_HI, tallyfile is opened READONLY */ -/* Otherwise, if on entry tallyfile doesn't exist, creation is attempted. */ - -static int get_tally( tally_t *tally, - uid_t uid, - const char *filename, - FILE **TALLY, - struct fail_s *fsp) - { - struct stat fileinfo; - int lstat_ret = lstat(filename,&fileinfo); - - if ( lstat_ret && *tally!=TALLY_HI ) { - int oldmask = umask(077); - *TALLY=fopen(filename, "a"); - /* Create file, or append-open in pathological case. */ - umask(oldmask); - if ( !*TALLY ) { - _pam_log(LOG_ALERT, "Couldn't create %s",filename); - return PAM_AUTH_ERR; - } - lstat_ret = fstat(fileno(*TALLY),&fileinfo); - fclose(*TALLY); - } - - if ( lstat_ret ) { - _pam_log(LOG_ALERT, "Couldn't stat %s",filename); - return PAM_AUTH_ERR; - } - - if((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) { - /* If the file is world writable or is not a - normal file, return error */ - _pam_log(LOG_ALERT, - "%s is either world writable or not a normal file", - filename); - return PAM_AUTH_ERR; - } - - if ( ! ( *TALLY = fopen(filename,(*tally!=TALLY_HI)?"r+":"r") ) ) { - _pam_log(LOG_ALERT, "Error opening %s for update", filename); - -/* Discovering why account service fails: e/uid are target user. - * - * perror(MODULE_NAME); - * fprintf(stderr,"uid %d euid %d\n",getuid(), geteuid()); - */ - return PAM_AUTH_ERR; - } - - if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) { - _pam_log(LOG_ALERT, "fseek failed %s", filename); - return PAM_AUTH_ERR; - } - - if ( fileinfo.st_size <= uid * sizeof(struct faillog) ) { - - memset(fsp, 0, sizeof(struct faillog)); - *tally=0; - fsp->fs_faillog.fail_time = time(NULL); - - } else if (( fread((char *) &fsp->fs_faillog, - sizeof(struct faillog), 1, *TALLY) )==0 ) { - - *tally=0; /* Assuming a gappy filesystem */ - - } else { - - *tally = fsp->fs_faillog.fail_cnt; - - } - - return PAM_SUCCESS; - } - -/*---------------------------------------------------------------------*/ - -/* --- Support function: update and close tallyfile with tally!=TALLY_HI --- */ - -static int set_tally( tally_t tally, - uid_t uid, - const char *filename, - FILE **TALLY, - struct fail_s *fsp) - { - if ( tally!=TALLY_HI ) - { - if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) { - _pam_log(LOG_ALERT, "fseek failed %s", filename); - return PAM_AUTH_ERR; - } - fsp->fs_faillog.fail_cnt = tally; - if (fwrite((char *) &fsp->fs_faillog, - sizeof(struct faillog), 1, *TALLY)==0 ) { - _pam_log(LOG_ALERT, "tally update (fwrite) failed.", filename); - return PAM_AUTH_ERR; - } - } - - if ( fclose(*TALLY) ) { - _pam_log(LOG_ALERT, "tally update (fclose) failed.", filename); - return PAM_AUTH_ERR; - } - *TALLY=NULL; - return PAM_SUCCESS; - } - -/*---------------------------------------------------------------------*/ - -/* --- PAM bits --- */ - -#ifndef MAIN - -#define PAM_FUNCTION(name) \ - PAM_EXTERN int name (pam_handle_t *pamh,int flags,int argc,const char **argv) - -#define RETURN_ERROR(i) return ((fail_on_error)?(i):(PAM_SUCCESS)) - -/*---------------------------------------------------------------------*/ - -/* --- tally bump function: bump tally for uid by (signed) inc --- */ - -static int tally_bump (int inc, - pam_handle_t *pamh, - int flags, - int argc, - const char **argv) { - uid_t uid; - - int - fail_on_error = FALSE; - tally_t - tally = 0; /* !TALLY_HI --> Log opened for update */ - - char - no_magic_root = FALSE; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { - FILE - *TALLY = NULL; - const char - *user = NULL, - *remote_host = NULL, - *cur_tty = NULL; - struct fail_s fs, *fsp = &fs; - - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); - - i=get_tally( &tally, uid, filename, &TALLY, fsp ); - - /* to remember old fail time (for locktime) */ - fsp->fs_fail_time = fsp->fs_faillog.fail_time; - fsp->fs_faillog.fail_time = time(NULL); - (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); - if (!remote_host) { - - (void) pam_get_item(pamh, PAM_TTY, (const void **)&cur_tty); - if (!cur_tty) { - strncpy(fsp->fs_faillog.fail_line, "unknown", - sizeof(fsp->fs_faillog.fail_line) - 1); - fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; - } else { - strncpy(fsp->fs_faillog.fail_line, cur_tty, - sizeof(fsp->fs_faillog.fail_line)-1); - fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; - } - - } else { - strncpy(fsp->fs_faillog.fail_line, remote_host, - (size_t)sizeof(fsp->fs_faillog.fail_line)); - fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0; - } - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ - - tally+=inc; - - if ( tally==TALLY_HI ) { /* Overflow *and* underflow. :) */ - tally-=inc; - _pam_log(LOG_ALERT,"Tally %sflowed for user %s", - (inc<0)?"under":"over",user); - } - } - - i=set_tally( tally, uid, filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - - return PAM_SUCCESS; -} - -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -PAM_FUNCTION( pam_sm_authenticate ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -/* --- Seems to need this function. Ho hum. --- */ - -PAM_FUNCTION( pam_sm_setcred ) { return PAM_SUCCESS; } - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- session management functions (only) --- */ - -/* - * Unavailable until .so files can be suid - */ - -#ifdef PAM_SM_SESSION - -/* To maintain a balance-tally of successful login/outs */ - -PAM_FUNCTION( pam_sm_open_session ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -PAM_FUNCTION( pam_sm_close_session ) { - return tally_bump(-1, pamh, flags, argc, argv); -} - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -/* To lock out a user with an unacceptably high tally */ - -PAM_FUNCTION( pam_sm_acct_mgmt ) { - uid_t - uid; - - int - fail_on_error = FALSE; - tally_t - deny = 0; - tally_t - tally = 0; /* !TALLY_HI --> Log opened for update */ - - char - no_magic_root = FALSE, - even_deny_root_account = FALSE; - char per_user = FALSE; /* if true then deny=.fail_max for user */ - char no_lock_time = FALSE; /* if true then don't use .fail_locktime */ - - const char - *user = NULL; - - enum TALLY_RESET - reset = TALLY_RESET_DEFAULT; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { - even_deny_root_account = TRUE; - } - else if ( ! strcmp( *argv, "reset" ) ) { - reset = TALLY_RESET_RESET; - } - else if ( ! strcmp( *argv, "no_reset" ) ) { - reset = TALLY_RESET_NO_RESET; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from != '/' || strlen(from) > FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strncmp( *argv, "deny=", 5 ) ) { - if ( sscanf((*argv)+5,TALLY_FMT,&deny) != 1 ) { - _pam_log(LOG_ERR,"bad number supplied; %s",*argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else if ( ! strcmp( *argv, "per_user" ) ) - { - per_user = TRUE; - } - else if ( ! strcmp( *argv, "no_lock_time") ) - { - no_lock_time = TRUE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { - struct fail_s fs, *fsp = &fs; - FILE *TALLY=0; - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); - - i=get_tally( &tally, uid, filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ - - /* To deny or not to deny; that is the question */ - - /* if there's .fail_max entry and per_user=TRUE then deny=.fail_max */ - - if ( (fsp->fs_faillog.fail_max) && (per_user) ) { - deny = fsp->fs_faillog.fail_max; - } - if (fsp->fs_faillog.fail_locktime && fsp->fs_fail_time - && (!no_lock_time) ) - { - if ( (fsp->fs_faillog.fail_locktime + fsp->fs_fail_time) > time(NULL) ) - { - _pam_log(LOG_NOTICE, - "user %s ("UID_FMT") has time limit [%lds left]" - " since last failure.", - user,uid, - fsp->fs_fail_time+fsp->fs_faillog.fail_locktime - -time(NULL)); - return PAM_AUTH_ERR; - } - } - if ( - ( deny != 0 ) && /* deny==0 means no deny */ - ( tally > deny ) && /* tally>deny means exceeded */ - ( even_deny_root_account || uid ) /* even_deny stops uid check */ - ) { - _pam_log(LOG_NOTICE,"user %s ("UID_FMT") tally "TALLY_FMT", deny "TALLY_FMT, - user, uid, tally, deny); - return PAM_AUTH_ERR; /* Only unconditional failure */ - } - - /* resets for explicit reset - * or by default if deny exists and not magic-root - */ - - if ( ( reset == TALLY_RESET_RESET ) || - ( reset == TALLY_RESET_DEFAULT && deny ) ) { tally=0; } - } - else /* is magic root */ { - - /* Magic root skips deny test... */ - - /* Magic root only resets on explicit reset, regardless of deny */ - - if ( reset == TALLY_RESET_RESET ) { tally=0; } - } - if (tally == 0) - { - fsp->fs_faillog.fail_time = (time_t) 0; - strcpy(fsp->fs_faillog.fail_line, ""); - } - i=set_tally( tally, uid, filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - - return PAM_SUCCESS; -} - -#endif /* #ifdef PAM_SM_AUTH */ - -/*-----------------------------------------------------------------------*/ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_tally_modstruct = { - MODULE_NAME, -#ifdef PAM_SM_AUTH - pam_sm_authenticate, - pam_sm_setcred, -#else - NULL, - NULL, -#endif -#ifdef PAM_SM_ACCOUNT - pam_sm_acct_mgmt, -#else - NULL, -#endif -#ifdef PAM_SM_SESSION - pam_sm_open_session, - pam_sm_close_session, -#else - NULL, - NULL, -#endif -#ifdef PAM_SM_PASSWORD - pam_sm_chauthtok, -#else - NULL, -#endif -}; - -#endif /* #ifdef PAM_STATIC */ - -/*-----------------------------------------------------------------------*/ - -#else /* #ifndef MAIN */ - -static const char *cline_filename = DEFAULT_LOGFILE; -static tally_t cline_reset = TALLY_HI; /* Default is `interrogate only' */ -static int cline_quiet = 0; - -/* - * Not going to link with pamlib just for these.. :) - */ - -static const char * pam_errors( int i ) { - switch (i) { - case PAM_AUTH_ERR: return "Authentication error"; - case PAM_SERVICE_ERR: return "Service error"; - case PAM_USER_UNKNOWN: return "Unknown user"; - default: return "Unknown error"; - } -} - -static int getopts( int argc, char **argv ) { - const char *pname = *argv; - for ( ; *argv ; (void)(*argv && ++argv) ) { - if ( !strcmp (*argv,"--file") ) cline_filename=*++argv; - else if ( !strncmp(*argv,"--file=",7) ) cline_filename=*argv+7; - else if ( !strcmp (*argv,"--user") ) cline_user=*++argv; - else if ( !strncmp(*argv,"--user=",7) ) cline_user=*argv+7; - else if ( !strcmp (*argv,"--reset") ) cline_reset=0; - else if ( !strncmp(*argv,"--reset=",8)) { - if ( sscanf(*argv+8,TALLY_FMT,&cline_reset) != 1 ) - fprintf(stderr,"%s: Bad number given to --reset=\n",pname), exit(0); - } - else if ( !strcmp (*argv,"--quiet") ) cline_quiet=1; - else { - fprintf(stderr,"%s: Unrecognised option %s\n",pname,*argv); - return FALSE; - } - } - return TRUE; -} - -int main ( int argc, char **argv ) { - - struct fail_s fs, *fsp = &fs; - - if ( ! getopts( argc, argv+1 ) ) { - printf("%s: [--file rooted-filename] [--user username] " - "[--reset[=n]] [--quiet]\n", - *argv); - exit(0); - } - - umask(077); - - /* - * Major difference between individual user and all users: - * --user just handles one user, just like PAM. - * --user=* handles all users, sniffing cline_filename for nonzeros - */ - - if ( cline_user ) { - uid_t uid; - tally_t tally=cline_reset; - FILE *TALLY=0; - int i=pam_get_uid( NULL, &uid, NULL); - if ( i != PAM_SUCCESS ) { - fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); - exit(0); - } - - i=get_tally( &tally, uid, cline_filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { - if (TALLY) fclose(TALLY); - fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); - exit(0); - } - - if ( !cline_quiet ) - printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",cline_user,uid, - (cline_reset!=TALLY_HI)?"had":"has",tally); - - i=set_tally( cline_reset, uid, cline_filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { - if (TALLY) fclose(TALLY); - fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); - exit(0); - } - } - else /* !cline_user (ie, operate on all users) */ { - FILE *TALLY=fopen(cline_filename, "r"); - uid_t uid=0; - if ( !TALLY ) perror(*argv), exit(0); - - for ( ; !feof(TALLY); uid++ ) { - tally_t tally; - struct passwd *pw; - if ( ! fread((char *) &fsp->fs_faillog, - sizeof (struct faillog), 1, TALLY) - || ! fsp->fs_faillog.fail_cnt ) { - continue; - } - tally = fsp->fs_faillog.fail_cnt; - - if ( ( pw=getpwuid(uid) ) ) { - printf("User %s\t("UID_FMT")\t%s "TALLY_FMT"\n",pw->pw_name,uid, - (cline_reset!=TALLY_HI)?"had":"has",tally); - } - else { - printf("User [NONAME]\t("UID_FMT")\t%s "TALLY_FMT"\n",uid, - (cline_reset!=TALLY_HI)?"had":"has",tally); - } - } - fclose(TALLY); - if ( cline_reset!=0 && cline_reset!=TALLY_HI ) { - fprintf(stderr,"%s: Can't reset all users to non-zero\n",*argv); - } - else if ( !cline_reset ) { - TALLY=fopen(cline_filename, "w"); - if ( !TALLY ) perror(*argv), exit(0); - fclose(TALLY); - } - } - return 0; -} - - -#endif diff --git a/modules/pam_tally/pam_tally_app.c b/modules/pam_tally/pam_tally_app.c deleted file mode 100644 index 9e6e1faf..00000000 --- a/modules/pam_tally/pam_tally_app.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - # This seemed like such a good idea at the time. :) - */ - -#define MAIN -#include "pam_tally.c" - diff --git a/modules/pam_time/.cvsignore b/modules/pam_time/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_time/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_time/Makefile b/modules/pam_time/Makefile deleted file mode 100644 index 9c2d0eb3..00000000 --- a/modules/pam_time/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# - -include ../../Make.Rules - -TITLE=pam_time -LOCAL_CONFILE=./time.conf -INSTALLED_CONFILE=$(SCONFIGD)/time.conf - -DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" -CFLAGS += $(DEFS) - -MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" -MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) -MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age - -include ../Simple.Rules diff --git a/modules/pam_time/README b/modules/pam_time/README deleted file mode 100644 index 38b2b3e6..00000000 --- a/modules/pam_time/README +++ /dev/null @@ -1,30 +0,0 @@ -$Id$ - -This is a help file for the pam_time module. It explains the need for -pam_time and also the syntax of the /etc/security/time.conf file. -[a lot of the syntax is freely adapted from the porttime file of the -shadow suite.] - -1. Introduction -=============== - -It is desirable to restrict access to a system and or specific -applications at various times of the day and on specific days or over -various terminal lines. - -The pam_time module is intended to offer a configurable module that -satisfies this purpose, within the context of Linux-PAM. - -2. the /etc/security/time.conf file -=================================== - -This file is the configuration script for defining time/port access -control to the system/applications. - -Its syntax is described in the sample ./time.conf provided in this -directory. - -unrecognised rules are ignored (but an error is logged to syslog(3)) - --------------------- -Bugs to Andrew <morgan@parc.power.net> or the list <pam-list@redhat.com> diff --git a/modules/pam_time/pam_time.c b/modules/pam_time/pam_time.c deleted file mode 100644 index 9cf68280..00000000 --- a/modules/pam_time/pam_time.c +++ /dev/null @@ -1,622 +0,0 @@ -/* pam_time module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/6/22 - * (File syntax and much other inspiration from the shadow package - * shadow-960129) - */ - -const static char rcsid[] = -"$Id$;\n" -"\t\tVersion 0.22 for Linux-PAM\n" -"Copyright (C) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; - -#include <security/_pam_aconf.h> - -#include <sys/file.h> -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <unistd.h> -#include <stdarg.h> -#include <time.h> -#include <syslog.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef DEFAULT_CONF_FILE -# define PAM_TIME_CONF DEFAULT_CONF_FILE /* from external define */ -#else -# define PAM_TIME_CONF "/etc/security/time.conf" -#endif -#define PAM_TIME_BUFLEN 1000 -#define FIELD_SEPARATOR ';' /* this is new as of .02 */ - -#ifdef TRUE -# undef TRUE -#endif -#ifdef FALSE -# undef FALSE -#endif - -typedef enum { FALSE, TRUE } boolean; -typedef enum { AND, OR } operator; - -/* - * here, we make definitions for the externally accessible functions - * in this file (these definitions are required for static modules - * but strongly encouraged generally) they are used to instruct the - * modules include file to define their prototypes. - */ - -#define PAM_SM_ACCOUNT - -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -/* --- static functions for checking whether the user should be let in --- */ - -static void _log_err(const char *format, ... ) -{ - va_list args; - - va_start(args, format); - openlog("pam_time", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(LOG_CRIT, format, args); - va_end(args); - closelog(); -} - -static void shift_bytes(char *mem, int from, int by) -{ - while (by-- > 0) { - *mem = mem[from]; - ++mem; - } -} - -static int read_field(int fd, char **buf, int *from, int *to) -{ - /* is buf set ? */ - - if (! *buf) { - *buf = (char *) malloc(PAM_TIME_BUFLEN); - if (! *buf) { - _log_err("out of memory"); - D(("no memory")); - return -1; - } - *from = *to = 0; - fd = open(PAM_TIME_CONF, O_RDONLY); - } - - /* do we have a file open ? return error */ - - if (fd < 0 && *to <= 0) { - _log_err( PAM_TIME_CONF " not opened"); - memset(*buf, 0, PAM_TIME_BUFLEN); - _pam_drop(*buf); - return -1; - } - - /* check if there was a newline last time */ - - if ((*to > *from) && (*to > 0) - && ((*buf)[*from] == '\0')) { /* previous line ended */ - (*from)++; - (*buf)[0] = '\0'; - return fd; - } - - /* ready for more data: first shift the buffer's remaining data */ - - *to -= *from; - shift_bytes(*buf, *from, *to); - *from = 0; - (*buf)[*to] = '\0'; - - while (fd >= 0 && *to < PAM_TIME_BUFLEN) { - int i; - - /* now try to fill the remainder of the buffer */ - - i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to); - if (i < 0) { - _log_err("error reading " PAM_TIME_CONF); - return -1; - } else if (!i) { - close(fd); - fd = -1; /* end of file reached */ - } else - *to += i; - - /* - * contract the buffer. Delete any comments, and replace all - * multiple spaces with single commas - */ - - i = 0; -#ifdef DEBUG_DUMP - D(("buffer=<%s>",*buf)); -#endif - while (i < *to) { - if ((*buf)[i] == ',') { - int j; - - for (j=++i; j<*to && (*buf)[j] == ','; ++j); - if (j!=i) { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - } - } - switch ((*buf)[i]) { - int j,c; - case '#': - for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); - if (j >= *to) { - (*buf)[*to = ++i] = '\0'; - } else if (c == '\n') { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - ++i; - } else { - _log_err("internal error in " __FILE__ - " at line %d", __LINE__ ); - return -1; - } - break; - case '\\': - if ((*buf)[i+1] == '\n') { - shift_bytes(i + *buf, 2, *to - (i+2)); - *to -= 2; - } else { - ++i; /* we don't escape non-newline characters */ - } - break; - case '!': - case ' ': - case '\t': - if ((*buf)[i] != '!') - (*buf)[i] = ','; - /* delete any trailing spaces */ - for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' - || c == '\t' ); ++j); - shift_bytes(i + *buf, j-i, (*to)-j ); - *to -= j-i; - break; - default: - ++i; - } - } - } - - (*buf)[*to] = '\0'; - - /* now return the next field (set the from/to markers) */ - { - int i; - - for (i=0; i<*to; ++i) { - switch ((*buf)[i]) { - case '#': - case '\n': /* end of the line/file */ - (*buf)[i] = '\0'; - *from = i; - return fd; - case FIELD_SEPARATOR: /* end of the field */ - (*buf)[i] = '\0'; - *from = ++i; - return fd; - } - } - *from = i; - (*buf)[*from] = '\0'; - } - - if (*to <= 0) { - D(("[end of text]")); - *buf = NULL; - } - - return fd; -} - -/* read a member from a field */ - -static int logic_member(const char *string, int *at) -{ - int len,c,to; - int done=0; - int token=0; - - len=0; - to=*at; - do { - c = string[to++]; - - switch (c) { - - case '\0': - --to; - done = 1; - break; - - case '&': - case '|': - case '!': - if (token) { - --to; - } - done = 1; - break; - - default: - if (isalpha(c) || c == '*' || isdigit(c) || c == '_' - || c == '-' || c == '.' || c == '/') { - token = 1; - } else if (token) { - --to; - done = 1; - } else { - ++*at; - } - } - } while (!done); - - return to - *at; -} - -typedef enum { VAL, OP } expect; - -static boolean logic_field(const void *me, const char *x, int rule, - boolean (*agrees)(const void *, const char * - , int, int)) -{ - boolean left=FALSE, right, not=FALSE; - operator oper=OR; - int at=0, l; - expect next=VAL; - - while ((l = logic_member(x,&at))) { - int c = x[at]; - - if (next == VAL) { - if (c == '!') - not = !not; - else if (isalpha(c) || c == '*') { - right = not ^ agrees(me, x+at, l, rule); - if (oper == AND) - left &= right; - else - left |= right; - next = OP; - } else { - _log_err("garbled syntax; expected name (rule #%d)", rule); - return FALSE; - } - } else { /* OP */ - switch (c) { - case '&': - oper = AND; - break; - case '|': - oper = OR; - break; - default: - _log_err("garbled syntax; expected & or | (rule #%d)" - , rule); - D(("%c at %d",c,at)); - return FALSE; - } - next = VAL; - } - at += l; - } - - return left; -} - -static boolean is_same(const void *A, const char *b, int len, int rule) -{ - int i; - const char *a; - - a = A; - for (i=0; len > 0; ++i, --len) { - if (b[i] != a[i]) { - if (b[i++] == '*') { - return (!--len || !strncmp(b+i,a+strlen(a)-len,len)); - } else - return FALSE; - } - } - return ( !len ); -} - -typedef struct { - int day; /* array of 7 bits, one set for today */ - int minute; /* integer, hour*100+minute for now */ -} TIME; - -struct day { - const char *d; - int bit; -} static const days[11] = { - { "su", 01 }, - { "mo", 02 }, - { "tu", 04 }, - { "we", 010 }, - { "th", 020 }, - { "fr", 040 }, - { "sa", 0100 }, - { "wk", 076 }, - { "wd", 0101 }, - { "al", 0177 }, - { NULL, 0 } -}; - -static TIME time_now(void) -{ - struct tm *local; - time_t the_time; - TIME this; - - the_time = time((time_t *)0); /* get the current time */ - local = localtime(&the_time); - this.day = days[local->tm_wday].bit; - this.minute = local->tm_hour*100 + local->tm_min; - - D(("day: 0%o, time: %.4d", this.day, this.minute)); - return this; -} - -/* take the current date and see if the range "date" passes it */ -static boolean check_time(const void *AT, const char *times, int len, int rule) -{ - boolean not,pass; - int marked_day, time_start, time_end; - const TIME *at; - int i,j=0; - - at = AT; - D(("chcking: 0%o/%.4d vs. %s", at->day, at->minute, times)); - - if (times == NULL) { - /* this should not happen */ - _log_err("internal error: " __FILE__ " line %d", __LINE__); - return FALSE; - } - - if (times[j] == '!') { - ++j; - not = TRUE; - } else { - not = FALSE; - } - - for (marked_day = 0; len > 0 && isalpha(times[j]); --len) { - int this_day=-1; - - D(("%c%c ?", times[j], times[j+1])); - for (i=0; days[i].d != NULL; ++i) { - if (tolower(times[j]) == days[i].d[0] - && tolower(times[j+1]) == days[i].d[1] ) { - this_day = days[i].bit; - break; - } - } - j += 2; - if (this_day == -1) { - _log_err("bad day specified (rule #%d)", rule); - return FALSE; - } - marked_day ^= this_day; - } - if (marked_day == 0) { - _log_err("no day specified"); - return FALSE; - } - D(("day range = 0%o", marked_day)); - - time_start = 0; - for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) { - time_start *= 10; - time_start += times[i+j]-'0'; /* is this portable? */ - } - j += i; - - if (times[j] == '-') { - time_end = 0; - for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) { - time_end *= 10; - time_end += times[i+j]-'0'; /* is this portable */ - } - j += i; - } else - time_end = -1; - - D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j])); - if (i != 5 || time_end == -1) { - _log_err("no/bad times specified (rule #%d)", rule); - return TRUE; - } - D(("times(%d to %d)", time_start,time_end)); - D(("marked_day = 0%o", marked_day)); - - /* compare with the actual time now */ - - pass = FALSE; - if (time_start < time_end) { /* start < end ? --> same day */ - if ((at->day & marked_day) && (at->minute >= time_start) - && (at->minute < time_end)) { - D(("time is listed")); - pass = TRUE; - } - } else { /* spans two days */ - if ((at->day & marked_day) && (at->minute >= time_start)) { - D(("caught on first day")); - pass = TRUE; - } else { - marked_day <<= 1; - marked_day |= (marked_day & 0200) ? 1:0; - D(("next day = 0%o", marked_day)); - if ((at->day & marked_day) && (at->minute <= time_end)) { - D(("caught on second day")); - pass = TRUE; - } - } - } - - return (not ^ pass); -} - -static int check_account(const char *service - , const char *tty, const char *user) -{ - int from=0,to=0,fd=-1; - char *buffer=NULL; - int count=0; - TIME here_and_now; - int retval=PAM_SUCCESS; - - here_and_now = time_now(); /* find current time */ - do { - boolean good=TRUE,intime; - - /* here we get the service name field */ - - fd = read_field(fd,&buffer,&from,&to); - - if (!buffer || !buffer[0]) { - /* empty line .. ? */ - continue; - } - ++count; - - good = logic_field(service, buffer, count, is_same); - D(("with service: %s", good ? "passes":"fails" )); - - /* here we get the terminal name field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_TIME_CONF "; no tty entry #%d", count); - continue; - } - good &= logic_field(tty, buffer, count, is_same); - D(("with tty: %s", good ? "passes":"fails" )); - - /* here we get the username field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_TIME_CONF "; no user entry #%d", count); - continue; - } - good &= logic_field(user, buffer, count, is_same); - D(("with user: %s", good ? "passes":"fails" )); - - /* here we get the time field */ - - fd = read_field(fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { - _log_err(PAM_TIME_CONF "; no time entry #%d", count); - continue; - } - - intime = logic_field(&here_and_now, buffer, count, check_time); - D(("with time: %s", intime ? "passes":"fails" )); - - fd = read_field(fd,&buffer,&from,&to); - if (buffer && buffer[0]) { - _log_err(PAM_TIME_CONF "; poorly terminated rule #%d", count); - continue; - } - - if (good && !intime) { - /* - * for security parse whole file.. also need to ensure - * that the buffer is free()'d and the file is closed. - */ - retval = PAM_PERM_DENIED; - } else { - D(("rule passed")); - } - } while (buffer); - - return retval; -} - -/* --- public account management functions --- */ - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - const char *service=NULL, *tty=NULL; - const char *user=NULL; - - /* set service name */ - - if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) - != PAM_SUCCESS || service == NULL) { - _log_err("cannot find the current service name"); - return PAM_ABORT; - } - - /* set username */ - - if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL - || *user == '\0') { - _log_err("cannot determine the user's name"); - return PAM_USER_UNKNOWN; - } - - /* set tty name */ - - if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS - || tty == NULL) { - D(("PAM_TTY not set, probing stdin")); - tty = ttyname(STDIN_FILENO); - if (tty == NULL) { - _log_err("couldn't get the tty name"); - return PAM_ABORT; - } - if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { - _log_err("couldn't set tty name"); - return PAM_ABORT; - } - } - - if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */ - tty += 5; - } - - /* good, now we have the service name, the user and the terminal name */ - - D(("service=%s", service)); - D(("user=%s", user)); - D(("tty=%s", tty)); - - return check_account(service,tty,user); -} - -/* end of module definition */ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_time_modstruct = { - "pam_time", - NULL, - NULL, - pam_sm_acct_mgmt, - NULL, - NULL, - NULL -}; -#endif diff --git a/modules/pam_time/time.conf b/modules/pam_time/time.conf deleted file mode 100644 index d2062fdb..00000000 --- a/modules/pam_time/time.conf +++ /dev/null @@ -1,64 +0,0 @@ -# this is an example configuration file for the pam_time module. Its syntax -# was initially based heavily on that of the shadow package (shadow-960129). -# -# the syntax of the lines is as follows: -# -# services;ttys;users;times -# -# white space is ignored and lines maybe extended with '\\n' (escaped -# newlines). As should be clear from reading these comments, -# text following a '#' is ignored to the end of the line. -# -# the combination of individual users/terminals etc is a logic list -# namely individual tokens that are optionally prefixed with '!' (logical -# not) and separated with '&' (logical and) and '|' (logical or). -# -# services -# is a logic list of PAM service names that the rule applies to. -# -# ttys -# is a logic list of terminal names that this rule applies to. -# -# users -# is a logic list of users to whom this rule applies. -# -# NB. For these items the simple wildcard '*' may be used only once. -# -# times -# the format here is a logic list of day/time-range -# entries the days are specified by a sequence of two character -# entries, MoTuSa for example is Monday Tuesday and Saturday. Note -# that repeated days are unset MoMo = no day, and MoWk = all weekdays -# bar Monday. The two character combinations accepted are -# -# Mo Tu We Th Fr Sa Su Wk Wd Al -# -# the last two being week-end days and all 7 days of the week -# respectively. As a final example, AlFr means all days except Friday. -# -# each day/time-range can be prefixed with a '!' to indicate "anything -# but" -# -# The time-range part is two 24-hour times HHMM separated by a hyphen -# indicating the start and finish time (if the finish time is smaller -# than the start time it is deemed to apply on the following day). -# -# for a rule to be active, ALL of service+ttys+users must be satisfied -# by the applying process. -# - -# -# Here is a simple example: running blank on tty* (any ttyXXX device), -# the users 'you' and 'me' are denied service all of the time -# - -#blank;tty* & !ttyp*;you|me;!Al0000-2400 - -# Another silly example, user 'root' is denied xsh access -# from pseudo terminals at the weekend and on mondays. - -#xsh;ttyp*;root;!WdMo0000-2400 - -# -# End of example file. -# \ No newline at end of file diff --git a/modules/pam_unix/.cvsignore b/modules/pam_unix/.cvsignore deleted file mode 100644 index 64c5ce5c..00000000 --- a/modules/pam_unix/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -dynamic -unix_chkpwd -*.so -*~ diff --git a/modules/pam_unix/CHANGELOG b/modules/pam_unix/CHANGELOG deleted file mode 100644 index 1476b579..00000000 --- a/modules/pam_unix/CHANGELOG +++ /dev/null @@ -1,55 +0,0 @@ -$Id$ - -* Mon Aug 16 1999 Jan Rêkorajski <baggins@pld.org.pl> -- fixed reentrancy problems - -* Sun Jul 4 21:03:42 PDT 1999 - -- temporarily removed the crypt16 stuff. I'm really paranoid about - crypto stuff and exporting it, and there are a few too many 's-box' - references in the code for my liking.. - -* Wed Jun 30 1999 Steve Langasek <vorlon@netexpress.net> -- further NIS+ fixes - -* Sun Jun 27 1999 Steve Langasek <vorlon@netexpress.net> -- fix to uid-handling code for NIS+ - -* Sat Jun 26 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- merged MD5 fix and early failure syslog - by Andrey Vladimirovich Savochkin <saw@msu.ru> -- minor fixes -- added signal handler to unix_chkpwd - -* Fri Jun 25 1999 Stephen Langasek <vorlon@netexpress.net> -- reorganized the code to let it build as separate C files - -* Sun Jun 20 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- fixes in pam_unix_auth, it incorrectly saved and restored return - value when likeauth option was used - -* Tue Jun 15 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- added NIS+ support - -* Mon Jun 14 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- total rewrite based on pam_pwdb module, now there is ONE pam_unix.so - module, it accepts the same options as pam_pwdb - all of them correctly ;) - (pam_pwdb dosn't understand what DISALLOW_NULL_AUTHTOK means) - -* Tue Apr 20 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- Arghhh, pam_unix_passwd was not updating /etc/shadow when used with - pam_cracklib. - -* Mon Apr 19 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- added "remember=XXX" option that means 'remember XXX old passwords' - Old passwords are stored in /etc/security/opasswd, there can be - maximum of 400 passwords per user. - -* Sat Mar 27 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- added crypt16 to pam_unix_auth and pam_unix_passwd (check only, this algorithm - is too lame to use it in real life) - -* Sun Mar 21 1999 Jan Rêkorajski <baggins@mimuw.edu.pl> -- pam_unix_auth now correctly behave when user has NULL AUTHTOK -- pam_unix_auth returns PAM_PERM_DENIED when seteuid fails - diff --git a/modules/pam_unix/Makefile b/modules/pam_unix/Makefile deleted file mode 100644 index e627d728..00000000 --- a/modules/pam_unix/Makefile +++ /dev/null @@ -1,167 +0,0 @@ -# $Id$ -# -# This Makefile controls a build process of the pam_unix modules -# for Linux-PAM. You should not modify this Makefile. -# - -include ../../Make.Rules - -######################################################################## -# some options... uncomment to take effect -######################################################################## - -# Unless someone wants to work out how to make this work with the new -# autoconf stuff, you should use a separate module for this type of thing -# pam_cracklib perhaps..? -# do you want cracklib? -#ifeq ($(HAVE_CRACKLIB),yes) -#USE_CRACKLIB=-D"USE_CRACKLIB" -#endif - -# do you want to use lckpwdf? -ifeq ($(WITH_LCKPWDF),yes) -USE_LCKPWDF=-D"USE_LCKPWDF" -# do you need to include the locking functions in the source? -ifeq ($(HAVE_LCKPWDF),no) - NEED_LCKPWDF=-D"NEED_LCKPWDF" -endif -endif - -ifeq ($(HAVE_LIBNSL),yes) - LIBNSL = -lnsl -endif - -ifeq ($(HAVE_LIBCRYPT),yes) - LIBCRYPT=-lcrypt -endif - -CHKPWD=unix_chkpwd - -EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" - -######################################################################## - -CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) -LDLIBS = $(EXTRALS) - -ifdef USE_CRACKLIB -CRACKLIB = -lcrack -endif - - -LIBOBJ = pam_unix_auth.o pam_unix_acct.o pam_unix_sess.o pam_unix_passwd.o \ - support.o -LIBSRC = pam_unix_auth.c pam_unix_acct.c pam_unix_sess.c pam_unix_passwd.c \ - support.c -LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) -LIBOBJS = $(addprefix static/,$(LIBOBJ)) - -PLUS = md5_good.o md5_broken.o md5_crypt_good.o md5_crypt_broken.o \ - yppasswd_xdr.o bigcrypt.o - -ifdef DYNAMIC -LIBSHARED = pam_unix.so -endif -ifdef STATIC -LIBSTATIC = libpam_unix.o -endif - - -########################### don't edit below ####################### - -all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register - -dynamic/%.o : %.c - $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -static/%.o: %.c - $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -dummy: - @echo "**** This is not a top-level Makefile " - exit - -info: - @echo - @echo "*** Building pam-unix module of the framework..." - @echo - -dirs: -ifdef DYNAMIC - mkdir -p ./dynamic -endif -ifdef STATIC - mkdir -p ./static -endif - -register: -ifdef STATIC - ( cd .. ; ./register_static pam_unix_auth pam_unix/$(LIBSTATIC) ; \ - ./register_static pam_unix_acct "" ; \ - ./register_static pam_unix_session "" ; \ - ./register_static pam_unix_passwd "" ; \ - ) -endif - -ifdef DYNAMIC -$(LIBOBJD): $(LIBSRC) - -$(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) -endif - -ifdef STATIC -$(LIBOBJS): $(LIBSRC) - -$(LIBSTATIC): $(LIBOBJS) - $(LD) -r -o $@ $(LIBOBJS) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) -endif - -$(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \ - md5_crypt_good.o md5_crypt_broken.o \ - bigcrypt.o - $(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) - -unix_chkpwd.o: unix_chkpwd.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -md5_good.o: md5.c - $(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_broken.o: md5.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_crypt_good.o: md5_crypt.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Good##x' \ - $(TARGET_ARCH) -c $< -o $@ - -md5_crypt_broken.o: md5_crypt.c - $(CC) $(CFLAGS) $(CPPFLAGS) -D'MD5Name(x)=Broken##x' \ - $(TARGET_ARCH) -c $< -o $@ - -install: all - mkdir -p $(FAKEROOT)$(SECUREDIR) -ifdef DYNAMIC - install -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) - for x in pam_unix_auth pam_unix_acct pam_unix_passwd pam_unix_session;\ - do ln -sf $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)/$$x.so ; done -endif - $(MKDIR) $(FAKEROOT)$(SUPLEMENTED) - install -m 4555 $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED) - -remove: - rm -f $(FAKEROOT)$(SECUREDIR)/$(LIBSHARED) - for x in pam_unix_auth pam_unix_acct pam_unix_passwd pam_unix_session;\ - do rm -f $(FAKEROOT)$(SECUREDIR)/$$x.so ; done - rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) - -clean: - rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core - rm -f *~ *.a *.out *.bak - rm -rf dynamic static - -.c.o: - $(CC) -c $(CFLAGS) $< - diff --git a/modules/pam_unix/README b/modules/pam_unix/README deleted file mode 100644 index d6b1f395..00000000 --- a/modules/pam_unix/README +++ /dev/null @@ -1,35 +0,0 @@ -pam_unix comes as one module pam_unix.so. - -The following links are left for compatibility with old versions: -pam_unix_auth: authentication module providing - pam_authenticate() and pam_setcred() hooks -pam_unix_sess: session module, providing session logging -pam_unix_acct: account management, providing shadow account - managment features, password aging etc.. -pam_unix_passwd: password updating facilities providing - cracklib password strength checking facilities. - -The following options are recognized: - debug - log more debugging info - audit - a little more extreme than debug - use_first_pass - don't prompt the user for passwords - take them from PAM_ items instead - try_first_pass - don't prompt the user for the passwords - unless PAM_(OLD)AUTHTOK is unset - use_authtok - like try_first_pass, but * fail * if the new - PAM_AUTHTOK has not been previously set. - (intended for stacking password modules only) - not_set_pass - don't set the PAM_ items with the passwords - used by this module. - shadow - try to maintian a shadow based system. - md5 - when a user changes their password next, - encrypt it with the md5 algorithm. - bigcrypt - when a user changes their password next, - excrypt it with the DEC C2 - algorithm(0). - nodelay - used to prevent failed authentication - resulting in a delay of about 1 second. - nis - use NIS RPC for setting new password - remember=X - remember X old passwords, they are kept in - /etc/security/opasswd in MD5 crypted form - - invalid arguments are logged to syslog. diff --git a/modules/pam_unix/bigcrypt.c b/modules/pam_unix/bigcrypt.c deleted file mode 100644 index 6b73f3d2..00000000 --- a/modules/pam_unix/bigcrypt.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This function implements the "bigcrypt" algorithm specifically for - * Linux-PAM. - * - * This algorithm is algorithm 0 (default) shipped with the C2 secure - * implementation of Digital UNIX. - * - * Disclaimer: This work is not based on the source code to Digital - * UNIX, nor am I connected to Digital Equipment Corp, in any way - * other than as a customer. This code is based on published - * interfaces and reasonable guesswork. - * - * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8 - * characters or less. Each block is encrypted using the standard UNIX - * libc crypt function. The result of the encryption for one block - * provides the salt for the suceeding block. - * - * Restrictions: The buffer used to hold the encrypted result is - * statically allocated. (see MAX_PASS_LEN below). This is necessary, - * as the returned pointer points to "static data that are overwritten - * by each call", (XPG3: XSI System Interface + Headers pg 109), and - * this is a drop in replacement for crypt(); - * - * Andy Phillips <atp@mssl.ucl.ac.uk> - */ - -#include <string.h> -#include <stdlib.h> -#include <security/_pam_macros.h> - -char *crypt(const char *key, const char *salt); -char *bigcrypt(const char *key, const char *salt); - -/* - * Max cleartext password length in segments of 8 characters this - * function can deal with (16 segments of 8 chars= max 128 character - * password). - */ - -#define MAX_PASS_LEN 16 -#define SEGMENT_SIZE 8 -#define SALT_SIZE 2 -#define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE) -#define ESEGMENT_SIZE 11 -#define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1) - -char *bigcrypt(const char *key, const char *salt) -{ - char *dec_c2_cryptbuf; - - unsigned long int keylen, n_seg, j; - char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr; - char keybuf[KEYBUF_SIZE + 1]; - - D(("called with key='%s', salt='%s'.", key, salt)); - - /* reset arrays */ - dec_c2_cryptbuf = malloc(CBUF_SIZE); - if (!dec_c2_cryptbuf) { - return NULL; - } - memset(keybuf, 0, KEYBUF_SIZE + 1); - memset(dec_c2_cryptbuf, 0, CBUF_SIZE); - - /* fill KEYBUF_SIZE with key */ - strncpy(keybuf, key, KEYBUF_SIZE); - - /* deal with case that we are doing a password check for a - conventially encrypted password: the salt will be - SALT_SIZE+ESEGMENT_SIZE long. */ - if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE)) - keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */ - - keylen = strlen(keybuf); - - if (!keylen) { - n_seg = 1; - } else { - /* work out how many segments */ - n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE); - } - - if (n_seg > MAX_PASS_LEN) - n_seg = MAX_PASS_LEN; /* truncate at max length */ - - /* set up some pointers */ - cipher_ptr = dec_c2_cryptbuf; - plaintext_ptr = keybuf; - - /* do the first block with supplied salt */ - tmp_ptr = crypt(plaintext_ptr, salt); /* libc crypt() */ - - /* and place in the static area */ - strncpy(cipher_ptr, tmp_ptr, 13); - cipher_ptr += ESEGMENT_SIZE + SALT_SIZE; - plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */ - - /* change the salt (1st 2 chars of previous block) - this was found - by dowsing */ - - salt_ptr = cipher_ptr - ESEGMENT_SIZE; - - /* so far this is identical to "return crypt(key, salt);", if - there is more than one block encrypt them... */ - - if (n_seg > 1) { - for (j = 2; j <= n_seg; j++) { - - tmp_ptr = crypt(plaintext_ptr, salt_ptr); - - /* skip the salt for seg!=0 */ - strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE); - - cipher_ptr += ESEGMENT_SIZE; - plaintext_ptr += SEGMENT_SIZE; - salt_ptr = cipher_ptr - ESEGMENT_SIZE; - } - } - D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf)); - - /* this is the <NUL> terminated encrypted password */ - - return dec_c2_cryptbuf; -} diff --git a/modules/pam_unix/lckpwdf.-c b/modules/pam_unix/lckpwdf.-c deleted file mode 100644 index b5ff4585..00000000 --- a/modules/pam_unix/lckpwdf.-c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This is a hack, but until libc and glibc both include this function - * by default (libc only includes it if nys is not being used, at the - * moment, and glibc doesn't appear to have it at all) we need to have - * it here, too. :-( - * - * This should not become an official part of PAM. - * - * BEGIN_HACK - */ - -/* - * lckpwdf.c -- prevent simultaneous updates of password files - * - * Before modifying any of the password files, call lckpwdf(). It may block - * for up to 15 seconds trying to get the lock. Return value is 0 on success - * or -1 on failure. When you are done, call ulckpwdf() to release the lock. - * The lock is also released automatically when the process exits. Only one - * process at a time may hold the lock. - * - * These functions are supposed to be conformant with AT&T SVID Issue 3. - * - * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, - * public domain. - */ - -#include <fcntl.h> -#include <signal.h> - -#define LOCKFILE "/etc/.pwd.lock" -#define TIMEOUT 15 - -static int lockfd = -1; - -static int set_close_on_exec(int fd) -{ - int flags = fcntl(fd, F_GETFD, 0); - if (flags == -1) - return -1; - flags |= FD_CLOEXEC; - return fcntl(fd, F_SETFD, flags); -} - -static int do_lock(int fd) -{ - struct flock fl; - - memset(&fl, 0, sizeof fl); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - return fcntl(fd, F_SETLKW, &fl); -} - -static void alarm_catch(int sig) -{ -/* does nothing, but fcntl F_SETLKW will fail with EINTR */ -} - -static int lckpwdf(void) -{ - struct sigaction act, oldact; - sigset_t set, oldset; - - if (lockfd != -1) - return -1; - - lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600); - if (lockfd == -1) - return -1; - if (set_close_on_exec(lockfd) == -1) - goto cleanup_fd; - - memset(&act, 0, sizeof act); - act.sa_handler = alarm_catch; - act.sa_flags = 0; - sigfillset(&act.sa_mask); - if (sigaction(SIGALRM, &act, &oldact) == -1) - goto cleanup_fd; - - sigemptyset(&set); - sigaddset(&set, SIGALRM); - if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1) - goto cleanup_sig; - - alarm(TIMEOUT); - if (do_lock(lockfd) == -1) - goto cleanup_alarm; - alarm(0); - sigprocmask(SIG_SETMASK, &oldset, NULL); - sigaction(SIGALRM, &oldact, NULL); - return 0; - - cleanup_alarm: - alarm(0); - sigprocmask(SIG_SETMASK, &oldset, NULL); - cleanup_sig: - sigaction(SIGALRM, &oldact, NULL); - cleanup_fd: - close(lockfd); - lockfd = -1; - return -1; -} - -static int ulckpwdf(void) -{ - unlink(LOCKFILE); - if (lockfd == -1) - return -1; - - if (close(lockfd) == -1) { - lockfd = -1; - return -1; - } - lockfd = -1; - return 0; -} -/* END_HACK */ diff --git a/modules/pam_unix/md5.c b/modules/pam_unix/md5.c deleted file mode 100644 index d88d6810..00000000 --- a/modules/pam_unix/md5.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * $Id$ - * - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - */ - -#include <string.h> -#include "md5.h" - -#ifndef HIGHFIRST -#define byteReverse(buf, len) /* Nothing */ -#else -static void byteReverse(unsigned char *buf, unsigned longs); - -#ifndef ASM_MD5 -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - uint32 t; - do { - t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Name(MD5Init)(struct MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301U; - ctx->buf[1] = 0xefcdab89U; - ctx->buf[2] = 0x98badcfeU; - ctx->buf[3] = 0x10325476U; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len) -{ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; - - MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -#ifndef ASM_MD5 - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16]) -{ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#endif diff --git a/modules/pam_unix/md5.h b/modules/pam_unix/md5.h deleted file mode 100644 index 103f168a..00000000 --- a/modules/pam_unix/md5.h +++ /dev/null @@ -1,31 +0,0 @@ - -#ifndef MD5_H -#define MD5_H - -typedef unsigned int uint32; - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -void GoodMD5Init(struct MD5Context *); -void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned); -void GoodMD5Final(unsigned char digest[16], struct MD5Context *); -void GoodMD5Transform(uint32 buf[4], uint32 const in[16]); -void BrokenMD5Init(struct MD5Context *); -void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned); -void BrokenMD5Final(unsigned char digest[16], struct MD5Context *); -void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]); - -char *Goodcrypt_md5(const char *pw, const char *salt); -char *Brokencrypt_md5(const char *pw, const char *salt); - -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ - -typedef struct MD5Context MD5_CTX; - -#endif /* MD5_H */ diff --git a/modules/pam_unix/md5_crypt.c b/modules/pam_unix/md5_crypt.c deleted file mode 100644 index 53972fcc..00000000 --- a/modules/pam_unix/md5_crypt.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * $Id$ - * - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * - * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp - * - */ - -#include <string.h> -#include <stdlib.h> -#include "md5.h" - -static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void to64(char *s, unsigned long v, int n) -{ - while (--n >= 0) { - *s++ = itoa64[v & 0x3f]; - v >>= 6; - } -} - -/* - * UNIX password - * - * Use MD5 for what it is best at... - */ - -char *MD5Name(crypt_md5)(const char *pw, const char *salt) -{ - const char *magic = "$1$"; - /* This string is magic for this algorithm. Having - * it this way, we can get get better later on */ - char *passwd, *p; - const char *sp, *ep; - unsigned char final[16]; - int sl, pl, i, j; - MD5_CTX ctx, ctx1; - unsigned long l; - - /* Refine the Salt first */ - sp = salt; - - /* TODO: now that we're using malloc'ed memory, get rid of the - strange constant buffer size. */ - passwd = malloc(120); - - /* If it starts with the magic string, then skip that */ - if (!strncmp(sp, magic, strlen(magic))) - sp += strlen(magic); - - /* It stops at the first '$', max 8 chars */ - for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) - continue; - - /* get the length of the true salt */ - sl = ep - sp; - - MD5Name(MD5Init)(&ctx); - - /* The password first, since that is what is most unknown */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw)); - - /* Then our magic string */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic)); - - /* Then the raw salt */ - MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl); - - /* Then just as many characters of the MD5(pw,salt,pw) */ - MD5Name(MD5Init)(&ctx1); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Final)(final,&ctx1); - for (pl = strlen(pw); pl > 0; pl -= 16) - MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); - - /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof final); - - /* Then something really weird... */ - for (j = 0, i = strlen(pw); i; i >>= 1) - if (i & 1) - MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1); - else - MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1); - - /* Now make the output string */ - strcpy(passwd, magic); - strncat(passwd, sp, sl); - strcat(passwd, "$"); - - MD5Name(MD5Final)(final,&ctx); - - /* - * and now, just to make sure things don't run too fast - * On a 60 Mhz Pentium this takes 34 msec, so you would - * need 30 seconds to build a 1000 entry dictionary... - */ - for (i = 0; i < 1000; i++) { - MD5Name(MD5Init)(&ctx1); - if (i & 1) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - else - MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); - - if (i % 3) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl); - - if (i % 7) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - - if (i & 1) - MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16); - else - MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw)); - MD5Name(MD5Final)(final,&ctx1); - } - - p = passwd + strlen(passwd); - - l = (final[0] << 16) | (final[6] << 8) | final[12]; - to64(p, l, 4); - p += 4; - l = (final[1] << 16) | (final[7] << 8) | final[13]; - to64(p, l, 4); - p += 4; - l = (final[2] << 16) | (final[8] << 8) | final[14]; - to64(p, l, 4); - p += 4; - l = (final[3] << 16) | (final[9] << 8) | final[15]; - to64(p, l, 4); - p += 4; - l = (final[4] << 16) | (final[10] << 8) | final[5]; - to64(p, l, 4); - p += 4; - l = final[11]; - to64(p, l, 2); - p += 2; - *p = '\0'; - - /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof final); - - return passwd; -} diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c deleted file mode 100644 index 178b6037..00000000 --- a/modules/pam_unix/pam_unix_acct.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright Elliot Lee, 1996. All rights reserved. - * Copyright Jan Rêkorajski, 1999. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <security/_pam_aconf.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <syslog.h> -#include <pwd.h> -#include <shadow.h> -#include <time.h> /* for time() */ - -#include <security/_pam_macros.h> - -/* indicate that the following groups are defined */ - -#define PAM_SM_ACCOUNT - -#include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include "support.h" - -/* - * PAM framework looks for this entry-point to pass control to the - * account management module. - */ - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - const char *uname; - int retval, daysleft; - time_t curdays; - struct spwd *spent; - struct passwd *pwent; - char buf[80]; - - D(("called.")); - - ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); - - retval = pam_get_item(pamh, PAM_USER, (const void **) &uname); - D(("user = `%s'", uname)); - if (retval != PAM_SUCCESS || uname == NULL) { - _log_err(LOG_ALERT, pamh - ,"could not identify user (from uid=%d)" - ,getuid()); - return PAM_USER_UNKNOWN; - } - - pwent = getpwnam(uname); - if (!pwent) { - _log_err(LOG_ALERT, pamh - ,"could not identify user (from getpwnam(%s))" - ,uname); - return PAM_USER_UNKNOWN; - } - - if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */ - uid_t save_euid, save_uid; - - save_euid = geteuid(); - save_uid = getuid(); - if (save_uid == pwent->pw_uid) - setreuid( save_euid, save_uid ); - else { - setreuid( 0, -1 ); - if (setreuid( -1, pwent->pw_uid ) == -1) { - setreuid( -1, 0 ); - setreuid( 0, -1 ); - if(setreuid( -1, pwent->pw_uid ) == -1) - return PAM_CRED_INSUFFICIENT; - } - } - spent = getspnam( uname ); - if (save_uid == pwent->pw_uid) - setreuid( save_uid, save_euid ); - else { - if (setreuid( -1, 0 ) == -1) - setreuid( save_uid, -1 ); - setreuid( -1, save_euid ); - } - - } else if (!strcmp( pwent->pw_passwd, "x" )) { - spent = getspnam(uname); - } else { - return PAM_SUCCESS; - } - - if (!spent) - return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ - - curdays = time(NULL) / (60 * 60 * 24); - D(("today is %d, last change %d", curdays, spent->sp_lstchg)); - if ((curdays > spent->sp_expire) && (spent->sp_expire != -1) - && (spent->sp_lstchg != 0)) { - _log_err(LOG_NOTICE, pamh - ,"account %s has expired (account expired)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "Your account has expired; please contact your system administrator"); - D(("account expired")); - return PAM_ACCT_EXPIRED; - } - if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact)) - && (spent->sp_max != -1) && (spent->sp_inact != -1) - && (spent->sp_lstchg != 0)) { - _log_err(LOG_NOTICE, pamh - ,"account %s has expired (failed to change password)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "Your account has expired; please contact your system administrator"); - D(("account expired 2")); - return PAM_ACCT_EXPIRED; - } - D(("when was the last change")); - if (spent->sp_lstchg == 0) { - _log_err(LOG_NOTICE, pamh - ,"expired password for user %s (root enforced)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "You are required to change your password immediately (root enforced)"); - D(("need a new password")); - return PAM_NEW_AUTHTOK_REQD; - } - if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) { - _log_err(LOG_DEBUG, pamh - ,"expired password for user %s (password aged)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "You are required to change your password immediately (password aged)"); - D(("need a new password 2")); - return PAM_NEW_AUTHTOK_REQD; - } - if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn)) - && (spent->sp_max != -1) && (spent->sp_warn != -1)) { - daysleft = (spent->sp_lstchg + spent->sp_max) - curdays; - _log_err(LOG_DEBUG, pamh - ,"password for user %s will expire in %d days" - ,uname, daysleft); - snprintf(buf, 80, "Warning: your password will expire in %d day%.2s", - daysleft, daysleft == 1 ? "" : "s"); - _make_remark(pamh, ctrl, PAM_TEXT_INFO, buf); - } - - D(("all done")); - - return PAM_SUCCESS; -} - - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_unix_acct_modstruct = { - "pam_unix_acct", - NULL, - NULL, - pam_sm_acct_mgmt, - NULL, - NULL, - NULL, -}; -#endif diff --git a/modules/pam_unix/pam_unix_auth.c b/modules/pam_unix/pam_unix_auth.c deleted file mode 100644 index 67497e06..00000000 --- a/modules/pam_unix/pam_unix_auth.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright Alexander O. Yuriev, 1996. All rights reserved. - * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de> - * Copyright Jan Rêkorajski, 1999. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* #define DEBUG */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> - -/* indicate the following groups are defined */ - -#define PAM_SM_AUTH - -#define _PAM_EXTERN_FUNCTIONS -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include "support.h" - -/* - * PAM framework looks for these entry-points to pass control to the - * authentication module. - */ - -/* Fun starts here :) - - * pam_sm_authenticate() performs UNIX/shadow authentication - * - * First, if shadow support is available, attempt to perform - * authentication using shadow passwords. If shadow is not - * available, or user does not have a shadow password, fallback - * onto a normal UNIX authentication - */ - -#define _UNIX_AUTHTOK "-UN*X-PASS" - -#define AUTH_RETURN \ -do { \ - if (on(UNIX_LIKE_AUTH, ctrl) && ret_data) { \ - D(("recording return code for next time [%d]", \ - retval)); \ - *ret_data = retval; \ - pam_set_data(pamh, "unix_setcred_return", \ - (void *) ret_data, setcred_free); \ - } \ - D(("done. [%s]", pam_strerror(pamh, retval))); \ - return retval; \ -} while (0) - - -static void setcred_free (pam_handle_t * pamh, void *ptr, int err) -{ - if (ptr) - free (ptr); -} - - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags - ,int argc, const char **argv) -{ - unsigned int ctrl; - int retval, *ret_data = NULL; - const char *name, *p; - - D(("called.")); - - ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); - - /* Get a few bytes so we can pass our return value to - pam_sm_setcred(). */ - if (on(UNIX_LIKE_AUTH, ctrl)) - ret_data = malloc(sizeof(int)); - - /* get the user'name' */ - - retval = pam_get_user(pamh, &name, NULL); - if (retval == PAM_SUCCESS) { - /* - * Various libraries at various times have had bugs related to - * '+' or '-' as the first character of a user name. Don't take - * any chances here. Require that the username starts with an - * alphanumeric character. - */ - if (name == NULL || !isalnum(*name)) { - _log_err(LOG_ERR, pamh, "bad username [%s]", name); - retval = PAM_USER_UNKNOWN; - AUTH_RETURN; - } - if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) - D(("username [%s] obtained", name)); - } else { - D(("trouble reading username")); - if (retval == PAM_CONV_AGAIN) { - D(("pam_get_user/conv() function is not ready yet")); - /* it is safe to resume this function so we translate this - * retval to the value that indicates we're happy to resume. - */ - retval = PAM_INCOMPLETE; - } - AUTH_RETURN; - } - - /* if this user does not have a password... */ - - if (_unix_blankpasswd(ctrl, name)) { - D(("user '%s' has blank passwd", name)); - name = NULL; - retval = PAM_SUCCESS; - AUTH_RETURN; - } - /* get this user's authentication token */ - - retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL - ,_UNIX_AUTHTOK, &p); - if (retval != PAM_SUCCESS) { - if (retval != PAM_CONV_AGAIN) { - _log_err(LOG_CRIT, pamh, "auth could not identify password for [%s]" - ,name); - } else { - D(("conversation function is not ready yet")); - /* - * it is safe to resume this function so we translate this - * retval to the value that indicates we're happy to resume. - */ - retval = PAM_INCOMPLETE; - } - name = NULL; - AUTH_RETURN; - } - D(("user=%s, password=[%s]", name, p)); - - /* verify the password of this user */ - retval = _unix_verify_password(pamh, name, p, ctrl); - name = p = NULL; - - AUTH_RETURN; -} - - -/* - * The only thing _pam_set_credentials_unix() does is initialization of - * UNIX group IDs. - * - * Well, everybody but me on linux-pam is convinced that it should not - * initialize group IDs, so I am not doing it but don't say that I haven't - * warned you. -- AOY - */ - -PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags - ,int argc, const char **argv) -{ - int retval; - int *pretval = NULL; - - D(("called.")); - - retval = PAM_SUCCESS; - - D(("recovering return code from auth call")); - /* We will only find something here if UNIX_LIKE_AUTH is set -- - don't worry about an explicit check of argv. */ - pam_get_data(pamh, "unix_setcred_return", (const void **) &pretval); - if(pretval) { - retval = *pretval; - pam_set_data(pamh, "unix_setcred_return", NULL, NULL); - D(("recovered data indicates that old retval was %d", retval)); - } - - return retval; -} - -#ifdef PAM_STATIC -struct pam_module _pam_unix_auth_modstruct = { - "pam_unix_auth", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; -#endif diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c deleted file mode 100644 index 6b51a6b2..00000000 --- a/modules/pam_unix/pam_unix_passwd.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. - * Copyright (C) 1996. - * Copyright (c) Jan Rêkorajski, 1999. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <malloc.h> -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <pwd.h> -#include <syslog.h> -#include <shadow.h> -#include <time.h> /* for time() */ -#include <fcntl.h> -#include <ctype.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <rpc/rpc.h> -#include <rpcsvc/yp_prot.h> -#include <rpcsvc/ypclnt.h> - -#ifdef USE_CRACKLIB -#include <crack.h> -#endif - -#include <security/_pam_macros.h> - -/* indicate the following groups are defined */ - -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include "yppasswd.h" -#include "md5.h" -#include "support.h" - -#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) -extern int getrpcport(const char *host, unsigned long prognum, - unsigned long versnum, unsigned int proto); -#endif /* GNU libc 2.1 */ - -/* - * PAM framework looks for these entry-points to pass control to the - * password changing module. - */ - -#ifdef NEED_LCKPWDF -#include "./lckpwdf.-c" -#endif - -extern char *bigcrypt(const char *key, const char *salt); - -/* - How it works: - Gets in username (has to be done) from the calling program - Does authentication of user (only if we are not running as root) - Gets new password/checks for sanity - Sets it. - */ - -/* passwd/salt conversion macros */ - -#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') -#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') - -/* data tokens */ - -#define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS" -#define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS" - -#define MAX_PASSWD_TRIES 3 -#define PW_TMPFILE "/etc/npasswd" -#define SH_TMPFILE "/etc/nshadow" -#define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict" -#define OPW_TMPFILE "/etc/security/nopasswd" -#define OLD_PASSWORDS_FILE "/etc/security/opasswd" - -/* - * i64c - convert an integer to a radix 64 character - */ -static int i64c(int i) -{ - if (i < 0) - return ('.'); - else if (i > 63) - return ('z'); - if (i == 0) - return ('.'); - if (i == 1) - return ('/'); - if (i >= 2 && i <= 11) - return ('0' - 2 + i); - if (i >= 12 && i <= 37) - return ('A' - 12 + i); - if (i >= 38 && i <= 63) - return ('a' - 38 + i); - return ('\0'); -} - -static char *crypt_md5_wrapper(const char *pass_new) -{ - /* - * Code lifted from Marek Michalkiewicz's shadow suite. (CG) - * removed use of static variables (AGM) - */ - - struct timeval tv; - MD5_CTX ctx; - unsigned char result[16]; - char *cp = (char *) result; - unsigned char tmp[16]; - int i; - char *x = NULL; - - GoodMD5Init(&ctx); - gettimeofday(&tv, (struct timezone *) 0); - GoodMD5Update(&ctx, (void *) &tv, sizeof tv); - i = getpid(); - GoodMD5Update(&ctx, (void *) &i, sizeof i); - i = clock(); - GoodMD5Update(&ctx, (void *) &i, sizeof i); - GoodMD5Update(&ctx, result, sizeof result); - GoodMD5Final(tmp, &ctx); - strcpy(cp, "$1$"); /* magic for the MD5 */ - cp += strlen(cp); - for (i = 0; i < 8; i++) - *cp++ = i64c(tmp[i] & 077); - *cp = '\0'; - - /* no longer need cleartext */ - x = Goodcrypt_md5(pass_new, (const char *) result); - - return x; -} - -static char *getNISserver(pam_handle_t *pamh) -{ - char *master; - char *domainname; - int port, err; - - if ((err = yp_get_default_domain(&domainname)) != 0) { - _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n", - yperr_string(err)); - return NULL; - } - if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) { - _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n", - yperr_string(err)); - return NULL; - } - port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); - if (port == 0) { - _log_err(LOG_WARNING, pamh, - "yppasswdd not running on NIS master host\n"); - return NULL; - } - if (port >= IPPORT_RESERVED) { - _log_err(LOG_WARNING, pamh, - "yppasswd daemon running on illegal port.\n"); - return NULL; - } - return master; -} - -static int check_old_password(const char *forwho, const char *newpass) -{ - static char buf[16384]; - char *s_luser, *s_uid, *s_npas, *s_pas; - int retval = PAM_SUCCESS; - FILE *opwfile; - - opwfile = fopen(OLD_PASSWORDS_FILE, "r"); - if (opwfile == NULL) - return PAM_AUTHTOK_ERR; - - while (fgets(buf, 16380, opwfile)) { - if (!strncmp(buf, forwho, strlen(forwho))) { - buf[strlen(buf) - 1] = '\0'; - s_luser = strtok(buf, ":,"); - s_uid = strtok(NULL, ":,"); - s_npas = strtok(NULL, ":,"); - s_pas = strtok(NULL, ":,"); - while (s_pas != NULL) { - char *md5pass = Goodcrypt_md5(newpass, s_pas); - if (!strcmp(md5pass, s_pas)) { - _pam_delete(md5pass); - retval = PAM_AUTHTOK_ERR; - break; - } - s_pas = strtok(NULL, ":,"); - _pam_delete(md5pass); - } - break; - } - } - fclose(opwfile); - - return retval; -} - -static int save_old_password(const char *forwho, const char *oldpass, - int howmany) -{ - static char buf[16384]; - static char nbuf[16384]; - char *s_luser, *s_uid, *s_npas, *s_pas, *pass; - int npas; - FILE *pwfile, *opwfile; - int err = 0; - int oldmask; - int found = 0; - struct passwd *pwd = NULL; - - if (howmany < 0) { - return PAM_SUCCESS; - } - - if (oldpass == NULL) { - return PAM_SUCCESS; - } - - oldmask = umask(077); - pwfile = fopen(OPW_TMPFILE, "w"); - umask(oldmask); - if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; - } - - opwfile = fopen(OLD_PASSWORDS_FILE, "r"); - if (opwfile == NULL) { - fclose(pwfile); - return PAM_AUTHTOK_ERR; - } - - chown(OPW_TMPFILE, 0, 0); - chmod(OPW_TMPFILE, 0600); - - while (fgets(buf, 16380, opwfile)) { - if (!strncmp(buf, forwho, strlen(forwho))) { - buf[strlen(buf) - 1] = '\0'; - s_luser = strtok(buf, ":"); - s_uid = strtok(NULL, ":"); - s_npas = strtok(NULL, ":"); - s_pas = strtok(NULL, ":"); - npas = strtol(s_npas, NULL, 10) + 1; - while (npas > howmany) { - s_pas = strpbrk(s_pas, ","); - if (s_pas != NULL) - s_pas++; - npas--; - } - pass = crypt_md5_wrapper(oldpass); - if (s_pas == NULL) - snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n", - s_luser, s_uid, npas, pass); - else - snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n", - s_luser, s_uid, npas, s_pas, pass); - _pam_delete(pass); - if (fputs(nbuf, pwfile) < 0) { - err = 1; - break; - } - found = 1; - } else if (fputs(buf, pwfile) < 0) { - err = 1; - break; - } - } - fclose(opwfile); - - if (!found) { - pwd = getpwnam(forwho); - if (pwd == NULL) { - err = 1; - } else { - pass = crypt_md5_wrapper(oldpass); - snprintf(nbuf, sizeof(nbuf), "%s:%d:1:%s\n", - forwho, pwd->pw_uid, pass); - _pam_delete(pass); - if (fputs(nbuf, pwfile) < 0) { - err = 1; - } - } - } - - if (fclose(pwfile)) { - D(("error writing entries to old passwords file: %s\n", - strerror(errno))); - err = 1; - } - - if (!err) { - rename(OPW_TMPFILE, OLD_PASSWORDS_FILE); - return PAM_SUCCESS; - } else { - unlink(OPW_TMPFILE); - return PAM_AUTHTOK_ERR; - } -} - -static int _update_passwd(pam_handle_t *pamh, - const char *forwho, const char *towhat) -{ - struct passwd *tmpent = NULL; - FILE *pwfile, *opwfile; - int err = 1; - int oldmask; - - oldmask = umask(077); - pwfile = fopen(PW_TMPFILE, "w"); - umask(oldmask); - if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; - } - - opwfile = fopen("/etc/passwd", "r"); - if (opwfile == NULL) { - fclose(pwfile); - return PAM_AUTHTOK_ERR; - } - - chown(PW_TMPFILE, 0, 0); - chmod(PW_TMPFILE, 0644); - tmpent = fgetpwent(opwfile); - while (tmpent) { - if (!strcmp(tmpent->pw_name, forwho)) { - /* To shut gcc up */ - union { - const char *const_charp; - char *charp; - } assigned_passwd; - assigned_passwd.const_charp = towhat; - - tmpent->pw_passwd = assigned_passwd.charp; - err = 0; - } - if (putpwent(tmpent, pwfile)) { - D(("error writing entry to password file: %s\n", strerror(errno))); - err = 1; - break; - } - tmpent = fgetpwent(opwfile); - } - fclose(opwfile); - - if (fclose(pwfile)) { - D(("error writing entries to password file: %s\n", strerror(errno))); - err = 1; - } - - if (!err) { - rename(PW_TMPFILE, "/etc/passwd"); - _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); - return PAM_SUCCESS; - } else { - unlink(PW_TMPFILE); - return PAM_AUTHTOK_ERR; - } -} - -static int _update_shadow(const char *forwho, char *towhat) -{ - struct spwd *spwdent = NULL, *stmpent = NULL; - FILE *pwfile, *opwfile; - int err = 1; - int oldmask; - - spwdent = getspnam(forwho); - if (spwdent == NULL) { - return PAM_USER_UNKNOWN; - } - oldmask = umask(077); - pwfile = fopen(SH_TMPFILE, "w"); - umask(oldmask); - if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; - } - - opwfile = fopen("/etc/shadow", "r"); - if (opwfile == NULL) { - fclose(pwfile); - return PAM_AUTHTOK_ERR; - } - - chown(SH_TMPFILE, 0, 0); - chmod(SH_TMPFILE, 0600); - stmpent = fgetspent(opwfile); - while (stmpent) { - - if (!strcmp(stmpent->sp_namp, forwho)) { - stmpent->sp_pwdp = towhat; - stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); - err = 0; - D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); - } - - if (putspent(stmpent, pwfile)) { - D(("error writing entry to shadow file: %s\n", strerror(errno))); - err = 1; - break; - } - - stmpent = fgetspent(opwfile); - } - fclose(opwfile); - - if (fclose(pwfile)) { - D(("error writing entries to shadow file: %s\n", strerror(errno))); - err = 1; - } - - if (!err) { - rename(SH_TMPFILE, "/etc/shadow"); - return PAM_SUCCESS; - } else { - unlink(SH_TMPFILE); - return PAM_AUTHTOK_ERR; - } -} - -static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, - char *towhat, unsigned int ctrl, int remember) -{ - struct passwd *pwd = NULL; - int retval = 0; - - D(("called")); - - setpwent(); - pwd = getpwnam(forwho); - endpwent(); - - if (pwd == NULL) - return PAM_AUTHTOK_ERR; - - if (on(UNIX_NIS, ctrl)) { - struct timeval timeout; - struct yppasswd yppwd; - CLIENT *clnt; - char *master; - int status; - int err = 0; - - /* Make RPC call to NIS server */ - if ((master = getNISserver(pamh)) == NULL) - return PAM_TRY_AGAIN; - - /* Initialize password information */ - yppwd.newpw.pw_passwd = pwd->pw_passwd; - yppwd.newpw.pw_name = pwd->pw_name; - yppwd.newpw.pw_uid = pwd->pw_uid; - yppwd.newpw.pw_gid = pwd->pw_gid; - yppwd.newpw.pw_gecos = pwd->pw_gecos; - yppwd.newpw.pw_dir = pwd->pw_dir; - yppwd.newpw.pw_shell = pwd->pw_shell; - yppwd.oldpass = fromwhat; - yppwd.newpw.pw_passwd = towhat; - - D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); - - /* The yppasswd.x file said `unix authentication required', - * so I added it. This is the only reason it is in here. - * My yppasswdd doesn't use it, but maybe some others out there - * do. --okir - */ - clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); - clnt->cl_auth = authunix_create_default(); - memset((char *) &status, '\0', sizeof(status)); - timeout.tv_sec = 25; - timeout.tv_usec = 0; - err = clnt_call(clnt, YPPASSWDPROC_UPDATE, - (xdrproc_t) xdr_yppasswd, (char *) &yppwd, - (xdrproc_t) xdr_int, (char *) &status, - timeout); - - if (err) { - clnt_perrno(err); - retval = PAM_TRY_AGAIN; - } else if (status) { - D(("Error while changing NIS password.\n")); - retval = PAM_TRY_AGAIN; - } - D(("The password has%s been changed on %s.", - (err || status) ? " not" : "", master)); - _log_err(LOG_NOTICE, pamh, "password%s changed for %s on %s", - (err || status) ? " not" : "", pwd->pw_name, master); - - auth_destroy(clnt->cl_auth); - clnt_destroy(clnt); - if ((err || status) != 0) { - retval = PAM_TRY_AGAIN; - } -#ifdef DEBUG - sleep(5); -#endif - return retval; - } - /* first, save old password */ - if (save_old_password(forwho, fromwhat, remember)) { - return PAM_AUTHTOK_ERR; - } - if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { - retval = _update_shadow(forwho, towhat); - if (retval == PAM_SUCCESS) - retval = _update_passwd(pamh, forwho, "x"); - } else { - retval = _update_passwd(pamh, forwho, towhat); - } - - return retval; -} - -static int _unix_verify_shadow(const char *user, unsigned int ctrl) -{ - struct passwd *pwd = NULL; /* Password and shadow password */ - struct spwd *spwdent = NULL; /* file entries for the user */ - time_t curdays; - int retval = PAM_SUCCESS; - - /* UNIX passwords area */ - setpwent(); - pwd = getpwnam(user); /* Get password file entry... */ - endpwent(); - if (pwd == NULL) - return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ - - if (strcmp(pwd->pw_passwd, "x") == 0) { - /* ...and shadow password file entry for this user, if shadowing - is enabled */ - setspent(); - spwdent = getspnam(user); - endspent(); - - if (spwdent == NULL) - return PAM_AUTHINFO_UNAVAIL; - } else { - if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ - uid_t save_uid; - - save_uid = geteuid(); - seteuid (pwd->pw_uid); - spwdent = getspnam( user ); - seteuid (save_uid); - - if (spwdent == NULL) - return PAM_AUTHINFO_UNAVAIL; - } else - spwdent = NULL; - } - - if (spwdent != NULL) { - /* We have the user's information, now let's check if their account - has expired (60 * 60 * 24 = number of seconds in a day) */ - - if (off(UNIX__IAMROOT, ctrl)) { - /* Get the current number of days since 1970 */ - curdays = time(NULL) / (60 * 60 * 24); - if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) - && (spwdent->sp_min != -1)) - retval = PAM_AUTHTOK_ERR; - else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) - && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1) - && (spwdent->sp_lstchg != 0)) - /* - * Their password change has been put off too long, - */ - retval = PAM_ACCT_EXPIRED; - else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1) - && (spwdent->sp_lstchg != 0)) - /* - * OR their account has just plain expired - */ - retval = PAM_ACCT_EXPIRED; - } - } - return retval; -} - -static int _pam_unix_approve_pass(pam_handle_t * pamh - ,unsigned int ctrl - ,const char *pass_old - ,const char *pass_new) -{ - const char *user; - const char *remark = NULL; - int retval = PAM_SUCCESS; - - D(("&new=%p, &old=%p", pass_old, pass_new)); - D(("new=[%s]", pass_new)); - D(("old=[%s]", pass_old)); - - if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) { - if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_DEBUG, pamh, "bad authentication token"); - } - _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? - "No password supplied" : "Password unchanged"); - return PAM_AUTHTOK_ERR; - } - /* - * if one wanted to hardwire authentication token strength - * checking this would be the place - AGM - */ - - retval = pam_get_item(pamh, PAM_USER, (const void **) &user); - if (retval != PAM_SUCCESS) { - if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_ERR, pamh, "Can not get username"); - return PAM_AUTHTOK_ERR; - } - } - if (off(UNIX__IAMROOT, ctrl)) { -#ifdef USE_CRACKLIB - remark = FascistCheck(pass_new, CRACKLIB_DICTS); - D(("called cracklib [%s]", remark)); -#else - if (strlen(pass_new) < 6) - remark = "You must choose a longer password"; - D(("lenth check [%s]", remark)); -#endif - if (on(UNIX_REMEMBER_PASSWD, ctrl)) - if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS) - remark = "Password has been already used. Choose another."; - } - if (remark) { - _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); - retval = PAM_AUTHTOK_ERR; - } - return retval; -} - - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl, lctrl; - int retval, i; - int remember = -1; - - /* <DO NOT free() THESE> */ - const char *user; - char *pass_old, *pass_new; - /* </DO NOT free() THESE> */ - - D(("called.")); - -#ifdef USE_LCKPWDF - /* our current locking system requires that we lock the - entire password database. This avoids both livelock - and deadlock. */ - /* These values for the number of attempts and the sleep time - are, of course, completely arbitrary. - My reading of the PAM docs is that, once pam_chauthtok() has been - called with PAM_UPDATE_AUTHTOK, we are obliged to take any - reasonable steps to make sure the token is updated; so retrying - for 1/10 sec. isn't overdoing it. - The other possibility is to call lckpwdf() on the first - pam_chauthtok() pass, and hold the lock until released in the - second pass--but is this guaranteed to work? -SRL */ - i=0; - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } -#endif - ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); - - /* - * First get the name of a user - */ - retval = pam_get_user(pamh, &user, "Username: "); - if (retval == PAM_SUCCESS) { - /* - * Various libraries at various times have had bugs related to - * '+' or '-' as the first character of a user name. Don't take - * any chances here. Require that the username starts with an - * alphanumeric character. - */ - if (user == NULL || !isalnum(*user)) { - _log_err(LOG_ERR, pamh, "bad username [%s]", user); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return PAM_USER_UNKNOWN; - } - if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) - _log_err(LOG_DEBUG, pamh, "username [%s] obtained", - user); - } else { - if (on(UNIX_DEBUG, ctrl)) - _log_err(LOG_DEBUG, pamh, - "password - could not identify user"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - - D(("Got username of %s", user)); - - /* - * This is not an AUTH module! - */ - if (on(UNIX__NONULL, ctrl)) - set(UNIX__NULLOK, ctrl); - - if (on(UNIX__PRELIM, ctrl)) { - /* - * obtain and verify the current password (OLDAUTHTOK) for - * the user. - */ - char *Announce; - - D(("prelim check")); - - if (_unix_blankpasswd(ctrl, user)) { -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return PAM_SUCCESS; - } else if (off(UNIX__IAMROOT, ctrl)) { - - /* instruct user what is happening */ -#define greeting "Changing password for " - Announce = (char *) malloc(sizeof(greeting) + strlen(user)); - if (Announce == NULL) { - _log_err(LOG_CRIT, pamh, - "password - out of memory"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return PAM_BUF_ERR; - } - (void) strcpy(Announce, greeting); - (void) strcpy(Announce + sizeof(greeting) - 1, user); -#undef greeting - - lctrl = ctrl; - set(UNIX__OLD_PASSWD, lctrl); - retval = _unix_read_password(pamh, lctrl - ,Announce - ,"(current) UNIX password: " - ,NULL - ,_UNIX_OLD_AUTHTOK - ,(const char **) &pass_old); - free(Announce); - - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh - ,"password - (old) token not obtained"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - /* verify that this is the password for this user */ - - retval = _unix_verify_password(pamh, user, pass_old, ctrl); - } else { - D(("process run by root so do nothing this time around")); - pass_old = NULL; - retval = PAM_SUCCESS; /* root doesn't have too */ - } - - if (retval != PAM_SUCCESS) { - D(("Authentication failed")); - pass_old = NULL; -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); - pass_old = NULL; - if (retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, - "failed to set PAM_OLDAUTHTOK"); - } - retval = _unix_verify_shadow(user, ctrl); - if (retval == PAM_AUTHTOK_ERR) { - if (off(UNIX__IAMROOT, ctrl)) - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "You must wait longer to change your password"); - else - retval = PAM_SUCCESS; - } - } else if (on(UNIX__UPDATE, ctrl)) { - /* - * tpass is used below to store the _pam_md() return; it - * should be _pam_delete()'d. - */ - - char *tpass = NULL; - int retry = 0; - - /* - * obtain the proposed password - */ - - D(("do update")); - - /* - * get the old token back. NULL was ok only if root [at this - * point we assume that this has already been enforced on a - * previous call to this function]. - */ - - if (off(UNIX_NOT_SET_PASS, ctrl)) { - retval = pam_get_item(pamh, PAM_OLDAUTHTOK - ,(const void **) &pass_old); - } else { - retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK - ,(const void **) &pass_old); - if (retval == PAM_NO_MODULE_DATA) { - retval = PAM_SUCCESS; - pass_old = NULL; - } - } - D(("pass_old [%s]", pass_old)); - - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - retval = _unix_verify_shadow(user, ctrl); - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - D(("get new password now")); - - lctrl = ctrl; - - if (on(UNIX_USE_AUTHTOK, lctrl)) { - set(UNIX_USE_FIRST_PASS, lctrl); - } - retry = 0; - retval = PAM_AUTHTOK_ERR; - while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { - /* - * use_authtok is to force the use of a previously entered - * password -- needed for pluggable password strength checking - */ - - retval = _unix_read_password(pamh, lctrl - ,NULL - ,"Enter new UNIX password: " - ,"Retype new UNIX password: " - ,_UNIX_NEW_AUTHTOK - ,(const char **) &pass_new); - - if (retval != PAM_SUCCESS) { - if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_ALERT, pamh - ,"password - new password not obtained"); - } - pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - D(("returned to _unix_chauthtok")); - - /* - * At this point we know who the user is and what they - * propose as their new password. Verify that the new - * password is acceptable. - */ - - if (pass_new[0] == '\0') { /* "\0" password = NULL */ - pass_new = NULL; - } - retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); - } - - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, - "new password not acceptable"); - pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - /* - * By reaching here we have approved the passwords and must now - * rebuild the password database file. - */ - - /* - * First we encrypt the new password. - */ - - if (on(UNIX_MD5_PASS, ctrl)) { - tpass = crypt_md5_wrapper(pass_new); - } else { - /* - * Salt manipulation is stolen from Rick Faith's passwd - * program. Sorry Rick :) -- alex - */ - - time_t tm; - char salt[3]; - - time(&tm); - salt[0] = bin_to_ascii(tm & 0x3f); - salt[1] = bin_to_ascii((tm >> 6) & 0x3f); - salt[2] = '\0'; - - if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { - /* - * to avoid using the _extensions_ of the bigcrypt() - * function we truncate the newly entered password - * [Problems that followed from this are fixed as per - * Bug 521314.] - */ - char *temp = malloc(9); - - if (temp == NULL) { - _log_err(LOG_CRIT, pamh, - "out of memory for password"); - pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return PAM_BUF_ERR; - } - /* copy first 8 bytes of password */ - strncpy(temp, pass_new, 8); - temp[8] = '\0'; - - /* no longer need cleartext */ - tpass = bigcrypt(temp, salt); - - _pam_delete(temp); /* tidy up */ - } else { - tpass = bigcrypt(pass_new, salt); - } - } - - D(("password processed")); - - /* update the password database(s) -- race conditions..? */ - - retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, - remember); - _pam_delete(tpass); - pass_old = pass_new = NULL; - } else { /* something has broken with the module */ - _log_err(LOG_ALERT, pamh, - "password received unknown request"); - retval = PAM_ABORT; - } - - D(("retval was %d", retval)); - -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; -} - - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_unix_passwd_modstruct = { - "pam_unix_passwd", - NULL, - NULL, - NULL, - NULL, - NULL, - pam_sm_chauthtok, -}; -#endif - diff --git a/modules/pam_unix/pam_unix_sess.c b/modules/pam_unix/pam_unix_sess.c deleted file mode 100644 index faef3e42..00000000 --- a/modules/pam_unix/pam_unix_sess.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * $Id$ - * - * Copyright Alexander O. Yuriev, 1996. All rights reserved. - * Copyright Jan Rêkorajski, 1999. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <security/_pam_aconf.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <syslog.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> - -/* indicate the following groups are defined */ - -#define PAM_SM_SESSION - -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include "support.h" - -/* - * PAM framework looks for these entry-points to pass control to the - * session module. - */ - -PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, - int argc, const char **argv) -{ - char *user_name, *service; - unsigned int ctrl; - int retval; - - D(("called.")); - - ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); - - retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, - "open_session - error recovering username"); - return PAM_SESSION_ERR; /* How did we get authenticated with - no username?! */ - } - retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, - "open_session - error recovering service"); - return PAM_SESSION_ERR; - } - _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)" - ,user_name - ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid()); - - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, - int argc, const char **argv) -{ - char *user_name, *service; - unsigned int ctrl; - int retval; - - D(("called.")); - - ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); - - retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, - "close_session - error recovering username"); - return PAM_SESSION_ERR; /* How did we get authenticated with - no username?! */ - } - retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, - "close_session - error recovering service"); - return PAM_SESSION_ERR; - } - _log_err(LOG_INFO, pamh, "session closed for user %s" - ,user_name); - - return PAM_SUCCESS; -} - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_unix_session_modstruct = { - "pam_unix_session", - NULL, - NULL, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; -#endif - diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c deleted file mode 100644 index 5998c7db..00000000 --- a/modules/pam_unix/support.c +++ /dev/null @@ -1,923 +0,0 @@ -/* - * $Id$ - * - * Copyright information at end of file. - */ - -#define _BSD_SOURCE - -#include <stdlib.h> -#include <unistd.h> -#include <stdarg.h> -#include <string.h> -#include <malloc.h> -#include <pwd.h> -#include <shadow.h> -#include <limits.h> -#include <utmp.h> -#include <errno.h> - -#include <security/_pam_macros.h> -#include <security/pam_modules.h> - -#include "md5.h" -#include "support.h" - -extern char *crypt(const char *key, const char *salt); -extern char *bigcrypt(const char *key, const char *salt); - -/* syslogging function for errors and other information */ - -void _log_err(int err, pam_handle_t *pamh, const char *format,...) -{ - char *service = NULL; - char logname[256]; - va_list args; - - pam_get_item(pamh, PAM_SERVICE, (const void **) &service); - if (service) { - strncpy(logname, service, sizeof(logname)); - logname[sizeof(logname) - 1 - strlen("(pam_unix)")] = '\0'; - strncat(logname, "(pam_unix)", strlen("(pam_unix)")); - } else { - strncpy(logname, "pam_unix", sizeof(logname) - 1); - } - - va_start(args, format); - openlog(logname, LOG_CONS | LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* this is a front-end for module-application conversations */ - -static int converse(pam_handle_t * pamh, int ctrl, int nargs - ,struct pam_message **message - ,struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) { - - retval = conv->conv(nargs, (const struct pam_message **) message - ,response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_DEBUG, pamh, "conversation failure [%s]" - ,pam_strerror(pamh, retval)); - } - } else if (retval != PAM_CONV_AGAIN) { - _log_err(LOG_ERR, pamh - ,"couldn't obtain coversation function [%s]" - ,pam_strerror(pamh, retval)); - } - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -int _make_remark(pam_handle_t * pamh, unsigned int ctrl - ,int type, const char *text) -{ - int retval = PAM_SUCCESS; - - if (off(UNIX__QUIET, ctrl)) { - struct pam_message *pmsg[1], msg[1]; - struct pam_response *resp; - - pmsg[0] = &msg[0]; - msg[0].msg = text; - msg[0].msg_style = type; - - resp = NULL; - retval = converse(pamh, ctrl, 1, pmsg, &resp); - - if (resp) { - _pam_drop_reply(resp, 1); - } - } - return retval; -} - - /* - * Beacause getlogin() is braindead and sometimes it just - * doesn't work, we reimplement it here. - */ -char *PAM_getlogin(void) -{ - struct utmp *ut, line; - char *curr_tty, *retval; - static char curr_user[sizeof(ut->ut_user) + 4]; - - retval = NULL; - - curr_tty = ttyname(0); - if (curr_tty != NULL) { - D(("PAM_getlogin ttyname: %s", curr_tty)); - curr_tty += 5; - setutent(); - strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); - if ((ut = getutline(&line)) != NULL) { - strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); - curr_user[sizeof(curr_user) - 1] = '\0'; - retval = curr_user; - } - endutent(); - } - D(("PAM_getlogin retval: %s", retval)); - - return retval; -} - -/* - * set the control flags for the UNIX module. - */ - -int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, - const char **argv) -{ - unsigned int ctrl; - - D(("called.")); - - ctrl = UNIX_DEFAULTS; /* the default selection of options */ - - /* set some flags manually */ - - if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) { - D(("IAMROOT")); - set(UNIX__IAMROOT, ctrl); - } - if (flags & PAM_UPDATE_AUTHTOK) { - D(("UPDATE_AUTHTOK")); - set(UNIX__UPDATE, ctrl); - } - if (flags & PAM_PRELIM_CHECK) { - D(("PRELIM_CHECK")); - set(UNIX__PRELIM, ctrl); - } - if (flags & PAM_DISALLOW_NULL_AUTHTOK) { - D(("DISALLOW_NULL_AUTHTOK")); - set(UNIX__NONULL, ctrl); - } - if (flags & PAM_SILENT) { - D(("SILENT")); - set(UNIX__QUIET, ctrl); - } - /* now parse the arguments to this module */ - - while (argc-- > 0) { - int j; - - D(("pam_unix arg: %s", *argv)); - - for (j = 0; j < UNIX_CTRLS_; ++j) { - if (unix_args[j].token - && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token))) { - break; - } - } - - if (j >= UNIX_CTRLS_) { - _log_err(LOG_ERR, pamh, - "unrecognized option [%s]", *argv); - } else { - ctrl &= unix_args[j].mask; /* for turning things off */ - ctrl |= unix_args[j].flag; /* for turning things on */ - - if (remember != NULL) { - if (j == UNIX_REMEMBER_PASSWD) { - *remember = strtol(*argv + 9, NULL, 10); - if ((*remember == LONG_MIN) || (*remember == LONG_MAX)) - *remember = -1; - if (*remember > 400) - *remember = 400; - } - } - } - - ++argv; /* step to next argument */ - } - - /* auditing is a more sensitive version of debug */ - - if (on(UNIX_AUDIT, ctrl)) { - set(UNIX_DEBUG, ctrl); - } - /* return the set of flags */ - - D(("done.")); - return ctrl; -} - -static void _cleanup(pam_handle_t * pamh, void *x, int error_status) -{ - _pam_delete(x); -} - -/* ************************************************************** * - * Useful non-trivial functions * - * ************************************************************** */ - - /* - * the following is used to keep track of the number of times a user fails - * to authenticate themself. - */ - -#define FAIL_PREFIX "-UN*X-FAIL-" -#define UNIX_MAX_RETRIES 3 - -struct _pam_failed_auth { - char *user; /* user that's failed to be authenticated */ - char *name; /* attempt from user with name */ - int uid; /* uid of calling user */ - int euid; /* euid of calling process */ - int count; /* number of failures so far */ -}; - -#ifndef PAM_DATA_REPLACE -#error "Need to get an updated libpam 0.52 or better" -#endif - -static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err) -{ - int quiet; - const char *service = NULL; - const char *ruser = NULL; - const char *rhost = NULL; - const char *tty = NULL; - struct _pam_failed_auth *failure; - - D(("called")); - - quiet = err & PAM_DATA_SILENT; /* should we log something? */ - err &= PAM_DATA_REPLACE; /* are we just replacing data? */ - failure = (struct _pam_failed_auth *) fl; - - if (failure != NULL) { - - if (!quiet && !err) { /* under advisement from Sun,may go away */ - - /* log the number of authentication failures */ - if (failure->count > 1) { - (void) pam_get_item(pamh, PAM_SERVICE, - (const void **)&service); - (void) pam_get_item(pamh, PAM_RUSER, - (const void **)&ruser); - (void) pam_get_item(pamh, PAM_RHOST, - (const void **)&rhost); - (void) pam_get_item(pamh, PAM_TTY, - (const void **)&tty); - _log_err(LOG_NOTICE, pamh, - "%d more authentication failure%s; " - "logname=%s uid=%d euid=%d " - "tty=%s ruser=%s rhost=%s " - "%s%s", - failure->count - 1, failure->count == 2 ? "" : "s", - failure->name, failure->uid, failure->euid, - tty ? tty : "", ruser ? ruser : "", - rhost ? rhost : "", - (failure->user && failure->user[0] != '\0') - ? " user=" : "", failure->user - ); - - if (failure->count > UNIX_MAX_RETRIES) { - _log_err(LOG_ALERT, pamh - ,"service(%s) ignoring max retries; %d > %d" - ,service == NULL ? "**unknown**" : service - ,failure->count - ,UNIX_MAX_RETRIES); - } - } - } - _pam_delete(failure->user); /* tidy up */ - _pam_delete(failure->name); /* tidy up */ - free(failure); - } -} - -/* - * _unix_blankpasswd() is a quick check for a blank password - * - * returns TRUE if user does not have a password - * - to avoid prompting for one in such cases (CG) - */ - -int _unix_blankpasswd(unsigned int ctrl, const char *name) -{ - struct passwd *pwd = NULL; - struct spwd *spwdent = NULL; - char *salt = NULL; - int retval; -#if HAVE_GETPWNAM_R - char *buf = NULL; - int bufsize = 0; - struct passwd pwd_buf; - - pwd = &pwd_buf; -#endif - - D(("called")); - - /* - * This function does not have to be too smart if something goes - * wrong, return FALSE and let this case to be treated somewhere - * else (CG) - */ - - if (on(UNIX__NONULL, ctrl)) - return 0; /* will fail but don't let on yet */ - - /* UNIX passwords area */ - - /* Get password file entry... */ -#if HAVE_GETPWNAM_R - bufsize = 1024; - buf = malloc(bufsize); - - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - while (retval == ERANGE) { - bufsize += 1024; - buf = realloc(buf, bufsize); - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - } -#else - pwd = getpwnam(name); -#endif - - if (pwd != NULL) { - if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) - { /* NIS+ */ - uid_t save_euid, save_uid; - - save_euid = geteuid(); - save_uid = getuid(); - if (save_uid == pwd->pw_uid) - setreuid( save_euid, save_uid ); - else { - setreuid( 0, -1 ); - if (setreuid( -1, pwd->pw_uid ) == -1) { - setreuid( -1, 0 ); - setreuid( 0, -1 ); - if(setreuid( -1, pwd->pw_uid ) == -1) - /* Will fail elsewhere. */ -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif - return 0; - } - } - - spwdent = getspnam( name ); - if (save_uid == pwd->pw_uid) - setreuid( save_uid, save_euid ); - else { - if (setreuid( -1, 0 ) == -1) - setreuid( save_uid, -1 ); - setreuid( -1, save_euid ); - } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { - /* - * ...and shadow password file entry for this user, - * if shadowing is enabled - */ - spwdent = getspnam(name); - } - if (spwdent) - salt = x_strdup(spwdent->sp_pwdp); - else - salt = x_strdup(pwd->pw_passwd); - } - /* Does this user have a password? */ - if (salt == NULL) { - retval = 0; - } else { - if (strlen(salt) == 0) - retval = 1; - else - retval = 0; - } - - /* tidy up */ - - if (salt) - _pam_delete(salt); - -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif - - return retval; -} - -/* - * verify the password of a user - */ - -#include <sys/types.h> -#include <sys/wait.h> - -static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, - unsigned int ctrl, const char *user) -{ - int retval, child, fds[2]; - - D(("called.")); - /* create a pipe for the password */ - if (pipe(fds) != 0) { - D(("could not make pipe")); - return PAM_AUTH_ERR; - } - - /* fork */ - child = fork(); - if (child == 0) { - static char *envp[] = { NULL }; - char *args[] = { NULL, NULL, NULL }; - - /* XXX - should really tidy up PAM here too */ - - /* reopen stdin as pipe */ - close(fds[1]); - dup2(fds[0], STDIN_FILENO); - - /* exec binary helper */ - args[0] = x_strdup(CHKPWD_HELPER); - args[1] = x_strdup(user); - - execve(CHKPWD_HELPER, args, envp); - - /* should not get here: exit with error */ - D(("helper binary is not available")); - exit(PAM_AUTHINFO_UNAVAIL); - } else if (child > 0) { - /* wait for child */ - /* if the stored password is NULL */ - if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ - write(fds[1], "nullok\0\0", 8); - } else { - write(fds[1], "nonull\0\0", 8); - } - if (passwd != NULL) { /* send the password to the child */ - write(fds[1], passwd, strlen(passwd)+1); - passwd = NULL; - } else { - write(fds[1], "", 1); /* blank password */ - } - close(fds[0]); /* close here to avoid possible SIGPIPE above */ - close(fds[1]); - (void) waitpid(child, &retval, 0); /* wait for helper to complete */ - retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR; - } else { - D(("fork failed")); - retval = PAM_AUTH_ERR; - } - - D(("returning %d", retval)); - return retval; -} - -int _unix_verify_password(pam_handle_t * pamh, const char *name - ,const char *p, unsigned int ctrl) -{ - struct passwd *pwd = NULL; - struct spwd *spwdent = NULL; - char *salt = NULL; - char *pp = NULL; - char *data_name; - int retval; - - D(("called")); - -#ifdef HAVE_PAM_FAIL_DELAY - if (off(UNIX_NODELAY, ctrl)) { - D(("setting delay")); - (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */ - } -#endif - - /* locate the entry for this user */ - - D(("locating user's record")); - - /* UNIX passwords area */ - pwd = getpwnam(name); /* Get password file entry... */ - - if (pwd != NULL) { - if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) - { /* NIS+ */ - uid_t save_euid, save_uid; - - save_euid = geteuid(); - save_uid = getuid(); - if (save_uid == pwd->pw_uid) - setreuid( save_euid, save_uid ); - else { - setreuid( 0, -1 ); - if (setreuid( -1, pwd->pw_uid ) == -1) { - setreuid( -1, 0 ); - setreuid( 0, -1 ); - if(setreuid( -1, pwd->pw_uid ) == -1) - return PAM_CRED_INSUFFICIENT; - } - } - - spwdent = getspnam( name ); - if (save_uid == pwd->pw_uid) - setreuid( save_uid, save_euid ); - else { - if (setreuid( -1, 0 ) == -1) - setreuid( save_uid, -1 ); - setreuid( -1, save_euid ); - } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { - /* - * ...and shadow password file entry for this user, - * if shadowing is enabled - */ - spwdent = getspnam(name); - } - if (spwdent) - salt = x_strdup(spwdent->sp_pwdp); - else - salt = x_strdup(pwd->pw_passwd); - } - - data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name)); - if (data_name == NULL) { - _log_err(LOG_CRIT, pamh, "no memory for data-name"); - } else { - strcpy(data_name, FAIL_PREFIX); - strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name); - } - - retval = PAM_SUCCESS; - if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) { - if (geteuid()) { - /* we are not root perhaps this is the reason? Run helper */ - D(("running helper binary")); - retval = _unix_run_helper_binary(pamh, p, ctrl, name); - if (pwd == NULL && !on(UNIX_AUDIT,ctrl) - && retval != PAM_SUCCESS) - { - name = NULL; - } - } else { - D(("user's record unavailable")); - if (on(UNIX_AUDIT, ctrl)) { - /* this might be a typo and the user has given a password - instead of a username. Careful with this. */ - _log_err(LOG_ALERT, pamh, - "check pass; user (%s) unknown", name); - } else { - name = NULL; - _log_err(LOG_ALERT, pamh, - "check pass; user unknown"); - } - p = NULL; - retval = PAM_AUTHINFO_UNAVAIL; - } - } else { - if (!strlen(salt)) { - /* the stored password is NULL */ - if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ - D(("user has empty password - access granted")); - retval = PAM_SUCCESS; - } else { - D(("user has empty password - access denied")); - retval = PAM_AUTH_ERR; - } - } else if (!p) { - retval = PAM_AUTH_ERR; - } else { - if (!strncmp(salt, "$1$", 3)) { - pp = Goodcrypt_md5(p, salt); - if (strcmp(pp, salt) != 0) { - _pam_delete(pp); - pp = Brokencrypt_md5(p, salt); - } - } else { - pp = bigcrypt(p, salt); - } - p = NULL; /* no longer needed here */ - - /* the moment of truth -- do we agree with the password? */ - D(("comparing state of pp[%s] and salt[%s]", pp, salt)); - - /* - * Note, we are comparing the bigcrypt of the password with - * the contents of the password field. If the latter was - * encrypted with regular crypt (and not bigcrypt) it will - * have been truncated for storage relative to the output - * of bigcrypt here. As such we need to compare only the - * stored string with the subset of bigcrypt's result. - * Bug 521314: The strncmp comparison is for legacy support. - */ - if (strncmp(pp, salt, strlen(salt)) == 0) { - retval = PAM_SUCCESS; - } else { - retval = PAM_AUTH_ERR; - } - } - } - - if (retval == PAM_SUCCESS) { - if (data_name) /* reset failures */ - pam_set_data(pamh, data_name, NULL, _cleanup_failures); - } else { - if (data_name != NULL) { - struct _pam_failed_auth *new = NULL; - const struct _pam_failed_auth *old = NULL; - - /* get a failure recorder */ - - new = (struct _pam_failed_auth *) - malloc(sizeof(struct _pam_failed_auth)); - - if (new != NULL) { - - new->user = x_strdup(name ? name : ""); - new->uid = getuid(); - new->euid = geteuid(); - new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : ""); - - /* any previous failures for this user ? */ - pam_get_data(pamh, data_name, (const void **) &old); - - if (old != NULL) { - new->count = old->count + 1; - if (new->count >= UNIX_MAX_RETRIES) { - retval = PAM_MAXTRIES; - } - } else { - const char *service=NULL; - const char *ruser=NULL; - const char *rhost=NULL; - const char *tty=NULL; - - (void) pam_get_item(pamh, PAM_SERVICE, - (const void **)&service); - (void) pam_get_item(pamh, PAM_RUSER, - (const void **)&ruser); - (void) pam_get_item(pamh, PAM_RHOST, - (const void **)&rhost); - (void) pam_get_item(pamh, PAM_TTY, - (const void **)&tty); - - _log_err(LOG_NOTICE, pamh, - "authentication failure; " - "logname=%s uid=%d euid=%d " - "tty=%s ruser=%s rhost=%s " - "%s%s", - new->name, new->uid, new->euid, - tty ? tty : "", - ruser ? ruser : "", - rhost ? rhost : "", - (new->user && new->user[0] != '\0') - ? " user=" : "", - new->user - ); - new->count = 1; - } - - pam_set_data(pamh, data_name, new, _cleanup_failures); - - } else { - _log_err(LOG_CRIT, pamh, - "no memory for failure recorder"); - } - } - } - - if (data_name) - _pam_delete(data_name); - if (salt) - _pam_delete(salt); - if (pp) - _pam_delete(pp); - - D(("done [%d].", retval)); - - return retval; -} - -/* - * obtain a password from the user - */ - -int _unix_read_password(pam_handle_t * pamh - ,unsigned int ctrl - ,const char *comment - ,const char *prompt1 - ,const char *prompt2 - ,const char *data_name - ,const char **pass) -{ - int authtok_flag; - int retval; - char *token; - - D(("called")); - - /* - * make sure nothing inappropriate gets returned - */ - - *pass = token = NULL; - - /* - * which authentication token are we getting? - */ - - authtok_flag = on(UNIX__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; - - /* - * should we obtain the password from a PAM item ? - */ - - if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) { - retval = pam_get_item(pamh, authtok_flag, (const void **) pass); - if (retval != PAM_SUCCESS) { - /* very strange. */ - _log_err(LOG_ALERT, pamh - ,"pam_get_item returned error to unix-read-password" - ); - return retval; - } else if (*pass != NULL) { /* we have a password! */ - return PAM_SUCCESS; - } else if (on(UNIX_USE_FIRST_PASS, ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } else if (on(UNIX_USE_AUTHTOK, ctrl) - && off(UNIX__OLD_PASSWD, ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - /* - * getting here implies we will have to get the password from the - * user directly. - */ - - { - struct pam_message msg[3], *pmsg[3]; - struct pam_response *resp; - int i, replies; - - /* prepare to converse */ - - if (comment != NULL && off(UNIX__QUIET, ctrl)) { - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = comment; - i = 1; - } else { - i = 0; - } - - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt1; - replies = 1; - - if (prompt2 != NULL) { - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt2; - ++replies; - } - /* so call the conversation expecting i responses */ - resp = NULL; - retval = converse(pamh, ctrl, i, pmsg, &resp); - - if (resp != NULL) { - - /* interpret the response */ - - if (retval == PAM_SUCCESS) { /* a good conversation */ - - token = x_strdup(resp[i - replies].resp); - if (token != NULL) { - if (replies == 2) { - - /* verify that password entered correctly */ - if (!resp[i - 1].resp - || strcmp(token, resp[i - 1].resp)) { - _pam_delete(token); /* mistyped */ - retval = PAM_AUTHTOK_RECOVER_ERR; - _make_remark(pamh, ctrl - ,PAM_ERROR_MSG, MISTYPED_PASS); - } - } - } else { - _log_err(LOG_NOTICE, pamh - ,"could not recover authentication token"); - } - - } - /* - * tidy up the conversation (resp_retcode) is ignored - * -- what is it for anyway? AGM - */ - - _pam_drop_reply(resp, i); - - } else { - retval = (retval == PAM_SUCCESS) - ? PAM_AUTHTOK_RECOVER_ERR : retval; - } - } - - if (retval != PAM_SUCCESS) { - if (on(UNIX_DEBUG, ctrl)) - _log_err(LOG_DEBUG, pamh, - "unable to obtain a password"); - return retval; - } - /* 'token' is the entered password */ - - if (off(UNIX_NOT_SET_PASS, ctrl)) { - - /* we store this password as an item */ - - retval = pam_set_item(pamh, authtok_flag, token); - _pam_delete(token); /* clean it up */ - if (retval != PAM_SUCCESS - || (retval = pam_get_item(pamh, authtok_flag - ,(const void **) pass)) - != PAM_SUCCESS) { - - *pass = NULL; - _log_err(LOG_CRIT, pamh, "error manipulating password"); - return retval; - - } - } else { - /* - * then store it as data specific to this module. pam_end() - * will arrange to clean it up. - */ - - retval = pam_set_data(pamh, data_name, (void *) token, _cleanup); - if (retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh - ,"error manipulating password data [%s]" - ,pam_strerror(pamh, retval)); - _pam_delete(token); - return retval; - } - *pass = token; - token = NULL; /* break link to password */ - } - - return PAM_SUCCESS; -} - -/* ****************************************************************** * - * Copyright (c) Jan Rêkorajski 1999. - * Copyright (c) Andrew G. Morgan 1996-8. - * Copyright (c) Alex O. Yuriev, 1996. - * Copyright (c) Cristian Gafton 1996. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h deleted file mode 100644 index 0b6b6e04..00000000 --- a/modules/pam_unix/support.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * $Id$ - */ - -#ifndef _PAM_UNIX_SUPPORT_H -#define _PAM_UNIX_SUPPORT_H - - -/* - * here is the string to inform the user that the new passwords they - * typed were not the same. - */ - -#define MISTYPED_PASS "Sorry, passwords do not match" - -/* type definition for the control options */ - -typedef struct { - const char *token; - unsigned int mask; /* shall assume 32 bits of flags */ - unsigned int flag; -} UNIX_Ctrls; - -/* - * macro to determine if a given flag is on - */ - -#define on(x,ctrl) (unix_args[x].flag & ctrl) - -/* - * macro to determine that a given flag is NOT on - */ - -#define off(x,ctrl) (!on(x,ctrl)) - -/* - * macro to turn on/off a ctrl flag manually - */ - -#define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag) -#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag)) - -/* the generic mask */ - -#define _ALL_ON_ (~0U) - -/* end of macro definitions definitions for the control flags */ - -/* ****************************************************************** * - * ctrl flags proper.. - */ - -/* - * here are the various options recognized by the unix module. They - * are enumerated here and then defined below. Internal arguments are - * given NULL tokens. - */ - -#define UNIX__OLD_PASSWD 0 /* internal */ -#define UNIX__VERIFY_PASSWD 1 /* internal */ -#define UNIX__IAMROOT 2 /* internal */ - -#define UNIX_AUDIT 3 /* print more things than debug.. - some information may be sensitive */ -#define UNIX_USE_FIRST_PASS 4 -#define UNIX_TRY_FIRST_PASS 5 -#define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */ - -#define UNIX__PRELIM 7 /* internal */ -#define UNIX__UPDATE 8 /* internal */ -#define UNIX__NONULL 9 /* internal */ -#define UNIX__QUIET 10 /* internal */ -#define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */ -#define UNIX_SHADOW 12 /* signal shadow on */ -#define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */ -#define UNIX__NULLOK 14 /* Null token ok */ -#define UNIX_DEBUG 15 /* send more info to syslog(3) */ -#define UNIX_NODELAY 16 /* admin does not want a fail-delay */ -#define UNIX_NIS 17 /* wish to use NIS for pwd */ -#define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */ -#define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */ -#define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */ -/* -------------- */ -#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */ - - -static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = -{ -/* symbol token name ctrl mask ctrl * - * ----------------------- ------------------- --------------------- -------- */ - -/* UNIX__OLD_PASSWD */ {NULL, _ALL_ON_, 01}, -/* UNIX__VERIFY_PASSWD */ {NULL, _ALL_ON_, 02}, -/* UNIX__IAMROOT */ {NULL, _ALL_ON_, 04}, -/* UNIX_AUDIT */ {"audit", _ALL_ON_, 010}, -/* UNIX_USE_FIRST_PASS */ {"use_first_pass", _ALL_ON_^(060), 020}, -/* UNIX_TRY_FIRST_PASS */ {"try_first_pass", _ALL_ON_^(060), 040}, -/* UNIX_NOT_SET_PASS */ {"not_set_pass", _ALL_ON_, 0100}, -/* UNIX__PRELIM */ {NULL, _ALL_ON_^(0600), 0200}, -/* UNIX__UPDATE */ {NULL, _ALL_ON_^(0600), 0400}, -/* UNIX__NONULL */ {NULL, _ALL_ON_, 01000}, -/* UNIX__QUIET */ {NULL, _ALL_ON_, 02000}, -/* UNIX_USE_AUTHTOK */ {"use_authtok", _ALL_ON_, 04000}, -/* UNIX_SHADOW */ {"shadow", _ALL_ON_, 010000}, -/* UNIX_MD5_PASS */ {"md5", _ALL_ON_^(0400000), 020000}, -/* UNIX__NULLOK */ {"nullok", _ALL_ON_^(01000), 0}, -/* UNIX_DEBUG */ {"debug", _ALL_ON_, 040000}, -/* UNIX_NODELAY */ {"nodelay", _ALL_ON_, 0100000}, -/* UNIX_NIS */ {"nis", _ALL_ON_^(010000), 0200000}, -/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000}, -/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000}, -/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000}, -}; - -#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) - - -/* use this to free strings. ESPECIALLY password strings */ - -#define _pam_delete(xx) \ -{ \ - _pam_overwrite(xx); \ - _pam_drop(xx); \ -} - -extern char *PAM_getlogin(void); -extern void _log_err(int err, pam_handle_t *pamh, const char *format,...); -extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl - ,int type, const char *text); -extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc, - const char **argv); -extern int _unix_blankpasswd(unsigned int ctrl, const char *name); -extern int _unix_verify_password(pam_handle_t * pamh, const char *name - ,const char *p, unsigned int ctrl); -extern int _unix_read_password(pam_handle_t * pamh - ,unsigned int ctrl - ,const char *comment - ,const char *prompt1 - ,const char *prompt2 - ,const char *data_name - ,const char **pass); - -#endif /* _PAM_UNIX_SUPPORT_H */ - diff --git a/modules/pam_unix/unix_chkpwd.c b/modules/pam_unix/unix_chkpwd.c deleted file mode 100644 index 9ba11041..00000000 --- a/modules/pam_unix/unix_chkpwd.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * $Id$ - * - * This program is designed to run setuid(root) or with sufficient - * privilege to read all of the unix password databases. It is designed - * to provide a mechanism for the current user (defined by this - * process' uid) to verify their own password. - * - * The password is read from the standard input. The exit status of - * this program indicates whether the user is authenticated or not. - * - * Copyright information is located at the end of the file. - * - */ - -#include <security/_pam_aconf.h> - -#ifdef MEMORY_DEBUG -# undef exit -# undef strdup -# undef free -#endif /* MEMORY_DEBUG */ - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <sys/types.h> -#include <pwd.h> -#include <shadow.h> -#include <signal.h> - -#define MAXPASS 200 /* the maximum length of a password */ - -#include <security/_pam_macros.h> - -#include "md5.h" - -extern char *crypt(const char *key, const char *salt); -extern char *bigcrypt(const char *key, const char *salt); - -#define UNIX_PASSED 0 -#define UNIX_FAILED 1 - -/* syslogging function for errors and other information */ - -static void _log_err(int err, const char *format,...) -{ - va_list args; - - va_start(args, format); - openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -static void su_sighandler(int sig) -{ - if (sig > 0) { - _log_err(LOG_NOTICE, "caught signal %d.", sig); - exit(sig); - } -} - -static void setup_signals(void) -{ - struct sigaction action; /* posix signal structure */ - - /* - * Setup signal handlers - */ - (void) memset((void *) &action, 0, sizeof(action)); - action.sa_handler = su_sighandler; - action.sa_flags = SA_RESETHAND; - (void) sigaction(SIGILL, &action, NULL); - (void) sigaction(SIGTRAP, &action, NULL); - (void) sigaction(SIGBUS, &action, NULL); - (void) sigaction(SIGSEGV, &action, NULL); - action.sa_handler = SIG_IGN; - action.sa_flags = 0; - (void) sigaction(SIGTERM, &action, NULL); - (void) sigaction(SIGHUP, &action, NULL); - (void) sigaction(SIGINT, &action, NULL); - (void) sigaction(SIGQUIT, &action, NULL); -} - -static int _unix_verify_password(const char *name, const char *p, int opt) -{ - struct passwd *pwd = NULL; - struct spwd *spwdent = NULL; - char *salt = NULL; - char *pp = NULL; - int retval = UNIX_FAILED; - - /* UNIX passwords area */ - setpwent(); - pwd = getpwnam(name); /* Get password file entry... */ - endpwent(); - if (pwd != NULL) { - if (strcmp(pwd->pw_passwd, "x") == 0) { - /* - * ...and shadow password file entry for this user, - * if shadowing is enabled - */ - setspent(); - spwdent = getspnam(name); - endspent(); - if (spwdent != NULL) - salt = x_strdup(spwdent->sp_pwdp); - else - pwd = NULL; - } else { - if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ - uid_t save_uid; - - save_uid = geteuid(); - seteuid(pwd->pw_uid); - spwdent = getspnam(name); - seteuid(save_uid); - - salt = x_strdup(spwdent->sp_pwdp); - } else { - salt = x_strdup(pwd->pw_passwd); - } - } - } - if (pwd == NULL || salt == NULL) { - _log_err(LOG_ALERT, "check pass; user unknown"); - p = NULL; - return retval; - } - - if (strlen(salt) == 0) - return (opt == 0) ? UNIX_FAILED : UNIX_PASSED; - - /* the moment of truth -- do we agree with the password? */ - retval = UNIX_FAILED; - if (!strncmp(salt, "$1$", 3)) { - pp = Goodcrypt_md5(p, salt); - if (strcmp(pp, salt) == 0) { - retval = UNIX_PASSED; - } else { - pp = Brokencrypt_md5(p, salt); - if (strcmp(pp, salt) == 0) - retval = UNIX_PASSED; - } - } else { - pp = bigcrypt(p, salt); - /* - * Note, we are comparing the bigcrypt of the password with - * the contents of the password field. If the latter was - * encrypted with regular crypt (and not bigcrypt) it will - * have been truncated for storage relative to the output - * of bigcrypt here. As such we need to compare only the - * stored string with the subset of bigcrypt's result. - * Bug 521314: the strncmp comparison is for legacy support. - */ - if (strncmp(pp, salt, strlen(salt)) == 0) { - retval = UNIX_PASSED; - } - } - p = NULL; /* no longer needed here */ - - /* clean up */ - { - char *tp = pp; - if (pp != NULL) { - while (tp && *tp) - *tp++ = '\0'; - free(pp); - } - pp = tp = NULL; - } - - return retval; -} - -static char *getuidname(uid_t uid) -{ - struct passwd *pw; - static char username[32]; - - pw = getpwuid(uid); - if (pw == NULL) - return NULL; - - strncpy(username, pw->pw_name, sizeof(username)); - username[sizeof(username) - 1] = '\0'; - - return username; -} - -int main(int argc, char *argv[]) -{ - char pass[MAXPASS + 1]; - char option[8]; - int npass, opt; - int force_failure = 0; - int retval = UNIX_FAILED; - char *user; - - /* - * Catch or ignore as many signal as possible. - */ - setup_signals(); - - /* - * we establish that this program is running with non-tty stdin. - * this is to discourage casual use. It does *NOT* prevent an - * intruder from repeatadly running this program to determine the - * password of the current user (brute force attack, but one for - * which the attacker must already have gained access to the user's - * account). - */ - - if (isatty(STDIN_FILENO)) { - - _log_err(LOG_NOTICE - ,"inappropriate use of Unix helper binary [UID=%d]" - ,getuid()); - fprintf(stderr - ,"This binary is not designed for running in this way\n" - "-- the system administrator has been informed\n"); - sleep(10); /* this should discourage/annoy the user */ - return UNIX_FAILED; - } - - /* - * determine the current user's name is - */ - user = getuidname(getuid()); - if (argc == 2) { - /* if the caller specifies the username, verify that user - matches it */ - if (strcmp(user, argv[1])) { - force_failure = 1; - } - } - - /* read the nullok/nonull option */ - - npass = read(STDIN_FILENO, option, 8); - - if (npass < 0) { - _log_err(LOG_DEBUG, "no option supplied"); - return UNIX_FAILED; - } else { - option[7] = '\0'; - if (strncmp(option, "nullok", 8) == 0) - opt = 1; - else - opt = 0; - } - - /* read the password from stdin (a pipe from the pam_unix module) */ - - npass = read(STDIN_FILENO, pass, MAXPASS); - - if (npass < 0) { /* is it a valid password? */ - - _log_err(LOG_DEBUG, "no password supplied"); - - } else if (npass >= MAXPASS) { - - _log_err(LOG_DEBUG, "password too long"); - - } else { - if (npass == 0) { - /* the password is NULL */ - - retval = _unix_verify_password(user, NULL, opt); - - } else { - /* does pass agree with the official one? */ - - pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_password(user, pass, opt); - - } - } - - memset(pass, '\0', MAXPASS); /* clear memory of the password */ - - /* return pass or fail */ - - if ((retval != UNIX_PASSED) || force_failure) { - return UNIX_FAILED; - } else { - return UNIX_PASSED; - } -} - -/* - * Copyright (c) Andrew G. Morgan, 1996. All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_unix/yppasswd.h b/modules/pam_unix/yppasswd.h deleted file mode 100644 index 6b414be0..00000000 --- a/modules/pam_unix/yppasswd.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * yppasswdd - * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de> - * - * This program is covered by the GNU General Public License, version 2. - * It is provided in the hope that it is useful. However, the author - * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details. - * - * This file was generated automatically by rpcgen from yppasswd.x, and - * editied manually. - */ - -#ifndef _YPPASSWD_H_ -#define _YPPASSWD_H_ - -#define YPPASSWDPROG ((u_long)100009) -#define YPPASSWDVERS ((u_long)1) -#define YPPASSWDPROC_UPDATE ((u_long)1) - -/* - * The password struct passed by the update call. I renamed it to - * xpasswd to avoid a type clash with the one defined in <pwd.h>. - */ -#ifndef __sgi -typedef struct xpasswd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; - char *pw_gecos; - char *pw_dir; - char *pw_shell; -} xpasswd; - -#else -#include <pwd.h> -typedef struct xpasswd xpasswd; -#endif - -/* The updated password information, plus the old password. - */ -typedef struct yppasswd { - char *oldpass; - xpasswd newpw; -} yppasswd; - -/* XDR encoding/decoding routines */ -bool_t xdr_xpasswd(XDR * xdrs, xpasswd * objp); -bool_t xdr_yppasswd(XDR * xdrs, yppasswd * objp); - -#endif /* _YPPASSWD_H_ */ diff --git a/modules/pam_unix/yppasswd_xdr.c b/modules/pam_unix/yppasswd_xdr.c deleted file mode 100644 index b1a60b4c..00000000 --- a/modules/pam_unix/yppasswd_xdr.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * yppasswdd - * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@monad.swb.de> - * - * This program is covered by the GNU General Public License, version 2. - * It is provided in the hope that it is useful. However, the author - * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details. - * - * This file was generated automatically by rpcgen from yppasswd.x, and - * editied manually. - */ - -#include <security/_pam_aconf.h> - -#include <rpc/rpc.h> -#include <rpcsvc/yp_prot.h> -#include <rpcsvc/ypclnt.h> -#include "yppasswd.h" - -bool_t -xdr_xpasswd(XDR * xdrs, xpasswd * objp) -{ - return xdr_string(xdrs, &objp->pw_name, ~0) - && xdr_string(xdrs, &objp->pw_passwd, ~0) - && xdr_int(xdrs, &objp->pw_uid) - && xdr_int(xdrs, &objp->pw_gid) - && xdr_string(xdrs, &objp->pw_gecos, ~0) - && xdr_string(xdrs, &objp->pw_dir, ~0) - && xdr_string(xdrs, &objp->pw_shell, ~0); -} - - -bool_t -xdr_yppasswd(XDR * xdrs, yppasswd * objp) -{ - return xdr_string(xdrs, &objp->oldpass, ~0) - && xdr_xpasswd(xdrs, &objp->newpw); -} diff --git a/modules/pam_userdb/.cvsignore b/modules/pam_userdb/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_userdb/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_userdb/Makefile b/modules/pam_userdb/Makefile deleted file mode 100644 index b53ac436..00000000 --- a/modules/pam_userdb/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). - -# $Id$ -# Created by Cristian Gafton <gafton@redhat.com> - -include ../../Make.Rules - -TITLE=pam_userdb - -ifeq ($(HAVE_NDBM_H),yes) - WHICH_DB=ndbm - ifeq ($(HAVE_LIBNDBM),yes) - MODULE_SIMPLE_EXTRALIBS = -lndbm - endif -else -ifeq ($(HAVE_LIBDB),yes) - WHICH_DB=db - MODULE_SIMPLE_EXTRALIBS = -ldb -else - WHICH_DB=none -endif -endif - -ifeq ($(WHICH_DB),none) - -include ../dont_makefile - -else - -MODULE_SIMPLE_EXTRAFILES = conv - -include ../Simple.Rules - -endif diff --git a/modules/pam_userdb/README b/modules/pam_userdb/README deleted file mode 100644 index 09d65edd..00000000 --- a/modules/pam_userdb/README +++ /dev/null @@ -1,30 +0,0 @@ -pam_userdb: - Look up users in a .db database and verify their password against - what is contained in that database. - -RECOGNIZED ARGUMENTS: - debug write a message to syslog indicating success or - failure. - - db=[path] use the [path] database for performing lookup. There - is no default; the module will return PAM_IGNORE if - no database is provided. - - icase make the password verification to be case insensitive - (ie when working with registration numbers and such) - - dump dump all the entries in the database to the log (eek, - don't do this by default!) - -MODULE SERVICES PROVIDED: - auth _authetication and _setcred (blank) - -EXAMPLE USE: - auth sufficient pam_userdb.so icase db=/tmp/dbtest.db - -AUTHOR: - Cristian Gafton <gafton@redhat.com> - - - -$Id$ diff --git a/modules/pam_userdb/conv.c b/modules/pam_userdb/conv.c deleted file mode 100644 index 0f13d03a..00000000 --- a/modules/pam_userdb/conv.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Conversation related functions - */ - -/* $Id */ -/* Copyright at the end of the file */ - -#define _BSD_SOURCE - -#include <stdlib.h> -#include <string.h> - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> - -#include "pam_userdb.h" - -/* - * dummy conversation function sending exactly one prompt - * and expecting exactly one response from the other party - */ -static int converse(pam_handle_t *pamh, - struct pam_message **message, - struct pam_response **response) -{ - int retval; - const struct pam_conv *conv; - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ; - if (retval == PAM_SUCCESS) - retval = conv->conv(1, (const struct pam_message **)message, - response, conv->appdata_ptr); - - return retval; /* propagate error status */ -} - - -static char *_pam_delete(register char *xx) -{ - _pam_overwrite(xx); - _pam_drop(xx); - return NULL; -} - -/* - * This is a conversation function to obtain the user's password - */ -int conversation(pam_handle_t *pamh) -{ - struct pam_message msg[2],*pmsg[2]; - struct pam_response *resp; - int retval; - char * token = NULL; - - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_PROMPT_ECHO_OFF; - msg[0].msg = "Password: "; - - /* so call the conversation expecting i responses */ - resp = NULL; - retval = converse(pamh, pmsg, &resp); - - if (resp != NULL) { - const char * item; - /* interpret the response */ - if (retval == PAM_SUCCESS) { /* a good conversation */ - token = x_strdup(resp[0].resp); - if (token == NULL) { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - - /* set the auth token */ - retval = pam_set_item(pamh, PAM_AUTHTOK, token); - token = _pam_delete(token); /* clean it up */ - if ( (retval != PAM_SUCCESS) || - (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item)) - != PAM_SUCCESS ) { - return retval; - } - - _pam_drop_reply(resp, 1); - } else { - retval = (retval == PAM_SUCCESS) - ? PAM_AUTHTOK_RECOVER_ERR:retval ; - } - - return retval; -} - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_userdb/create.pl b/modules/pam_userdb/create.pl deleted file mode 100644 index 046b55f0..00000000 --- a/modules/pam_userdb/create.pl +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/perl -# this program creates a database in ARGV[1] from pairs given on -# stdandard input -# -# $Id$ - -use DB_File; - -my $database = $ARGV[0]; -die "Use: check,pl <database>\n" unless ($database); -print "Using database: $database\n"; - -my %lusers = (); - -tie %lusers, 'DB_File', $database, O_RDWR|O_CREAT, 0644, $DB_HASH ; -while (<STDIN>) { - my ($user, $pass) = split; - - $lusers{$user} = $pass; -} -untie %lusers; - - diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c deleted file mode 100644 index 519ee898..00000000 --- a/modules/pam_userdb/pam_userdb.c +++ /dev/null @@ -1,307 +0,0 @@ -/* pam_userdb module */ - -/* - * $Id$ - * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 - * See the end of the file for Copyright Information - */ - -#include <security/_pam_aconf.h> - -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> - -#include "pam_userdb.h" - -#ifdef HAVE_NDBM_H -# include <ndbm.h> -#else -# ifdef HAVE_DB_H -# define DB_DBM_HSEARCH 1 /* use the dbm interface */ -# include <db.h> -# else -# error "failed to find a libdb or equivalent" -# endif -#endif - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT - -#include <security/pam_modules.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -char * database = NULL; -static int ctrl = 0; - -static int _pam_parse(int argc, const char **argv) -{ - /* step through arguments */ - for (ctrl = 0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strcasecmp(*argv, "icase")) - ctrl |= PAM_ICASE_ARG; - else if (!strcasecmp(*argv, "dump")) - ctrl |= PAM_DUMP_ARG; - else if (!strncasecmp(*argv,"db=", 3)) { - database = strdup((*argv) + 3); - if (database == NULL) - _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", - *argv); - } else { - _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); - } - } - - return ctrl; -} - - -/* - * Looks up an user name in a database and checks the password - * - * return values: - * 1 = User not found - * 0 = OK - * -1 = Password incorrect - * -2 = System error - */ -static int user_lookup(const char *user, const char *pass) -{ - DBM *dbm; - datum key, data; - - /* Open the DB file. */ - dbm = dbm_open(database, O_RDONLY, 0644); - if (dbm == NULL) { - _pam_log(LOG_ERR, "user_lookup: could not open database `%s'", - database); - return -2; - } - - if (ctrl &PAM_DUMP_ARG) { - _pam_log(LOG_INFO, "Database dump:"); - for (key = dbm_firstkey(dbm); key.dptr != NULL; - key = dbm_nextkey(dbm)) { - data = dbm_fetch(dbm, key); - _pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'", - key.dsize, key.dptr, data.dsize, data.dptr); - } - } - /* do some more init work */ - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.dptr = x_strdup(user); - key.dsize = strlen(user); - user = NULL; - - if (key.dptr) { - data = dbm_fetch(dbm, key); - memset(key.dptr, 0, key.dsize); - free(key.dptr); - } - - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_INFO, "password in database is [%p]`%s', len is %d", - data.dptr, (char *) data.dptr, data.dsize); - } - - if (data.dptr != NULL) { - int compare = 0; - - if (strlen(pass) != data.dsize) { - compare = 1; - } else if (ctrl & PAM_ICASE_ARG) { - compare = strncasecmp(data.dptr, pass, data.dsize); - } else { - compare = strncmp(data.dptr, pass, data.dsize); - } - dbm_close(dbm); - if (compare == 0) - return 0; /* match */ - else - return -1; /* wrong */ - } else { - if (ctrl & PAM_DEBUG_ARG) { - _pam_log(LOG_INFO, "error returned by dbm_fetch: %s", - strerror(errno)); - } - dbm_close(dbm); - /* probably we should check dbm_error() here */ - return 1; /* not found */ - } - - /* NOT REACHED */ - return -2; -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - const char *username; - const char *password; - int retval = PAM_AUTH_ERR; - - /* parse arguments */ - ctrl = _pam_parse(argc, argv); - - /* Get the username */ - retval = pam_get_user(pamh, &username, NULL); - if ((retval != PAM_SUCCESS) || (!username)) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG,"can not get the username"); - return PAM_SERVICE_ERR; - } - - /* Converse just to be sure we have the password */ - retval = conversation(pamh); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "could not obtain password for `%s'", - username); - return -2; - } - - /* Get the password */ - retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "Could not retrive user's password"); - return -2; - } - - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", - username, password); - - /* Now use the username to look up password in the database file */ - retval = user_lookup(username, password); - switch (retval) { - case -2: - /* some sort of system error. The log was already printed */ - return PAM_SERVICE_ERR; - case -1: - /* incorrect password */ - _pam_log(LOG_WARNING, - "user `%s' denied access (incorrect password)", - username); - return PAM_AUTH_ERR; - case 1: - /* the user does not exist in the database */ - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE, "user `%s' not found in the database", - username); - return PAM_USER_UNKNOWN; - case 0: - /* Otherwise, the authentication looked good */ - _pam_log(LOG_NOTICE, "user '%s' granted acces", username); - return PAM_SUCCESS; - default: - /* we don't know anything about this return value */ - _pam_log(LOG_ERR, - "internal module error (retval = %d, user = `%s'", - retval, username); - return PAM_SERVICE_ERR; - } - - /* should not be reached */ - return PAM_IGNORE; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - return PAM_SUCCESS; -} - -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - return PAM_SUCCESS; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_userdb_modstruct = { - "pam_userdb", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_userdb/pam_userdb.h b/modules/pam_userdb/pam_userdb.h deleted file mode 100644 index 911a7622..00000000 --- a/modules/pam_userdb/pam_userdb.h +++ /dev/null @@ -1,61 +0,0 @@ - -#ifndef _PAM_USERSDB_H -#define _PAM_USERSDB_H -/* $Id$ */ - -/* Header files */ -#include <security/pam_appl.h> - -/* argument parsing */ -#define PAM_DEBUG_ARG 0x0001 -#define PAM_ICASE_ARG 0x0002 -#define PAM_DUMP_ARG 0x0004 - -/* Useful macros */ -#define x_strdup(s) ( (s) ? strdup(s):NULL ) - -/* The name of the module we are compiling */ -#ifndef MODULE_NAME -#define MODULE_NAME "pam_userdb" -#endif /* MODULE_NAME */ - -/* function prototypes */ -int conversation(pam_handle_t *); - -#endif /* _PAM_USERSDB_H */ - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999 - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pam_warn/.cvsignore b/modules/pam_warn/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_warn/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_warn/Makefile b/modules/pam_warn/Makefile deleted file mode 100644 index 44c56f17..00000000 --- a/modules/pam_warn/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_warn - -include ../Simple.Rules diff --git a/modules/pam_warn/README b/modules/pam_warn/README deleted file mode 100644 index 6d484bdf..00000000 --- a/modules/pam_warn/README +++ /dev/null @@ -1,26 +0,0 @@ -# $Id$ -# - -This module is an authentication module that does not authenticate. -Instead it always returns PAM_IGNORE, indicating that it does not want -to affect the authentication process. - -Its purpose is to log a message to the syslog indicating the -pam_item's available at the time it was invoked. It is a diagnostic -tool. - -Recognized arguments: - - <none> - -module services provided: - - auth _authenticate and _setcred (blank) - acct _acct_mgmt [mapped to _authenticate] - session _open_session and - _close_session [mapped to _authenticate ] - password _chauthtok [mapped to _authenticate] - - -Andrew Morgan -1996/11/14 diff --git a/modules/pam_warn/pam_warn.c b/modules/pam_warn/pam_warn.c deleted file mode 100644 index f167ea91..00000000 --- a/modules/pam_warn/pam_warn.c +++ /dev/null @@ -1,127 +0,0 @@ -/* pam_warn module */ - -/* - * $Id$ - * - * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 - */ - -#define _BSD_SOURCE - -#include <stdio.h> -#include <unistd.h> -#include <syslog.h> -#include <stdarg.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH -#define PAM_SM_PASSWORD - -#include <security/pam_modules.h> - -/* some syslogging */ - -#define OBTAIN(item, value, default_value) do { \ - (void) pam_get_item(pamh, item, (const void **) &value); \ - value = value ? value : default_value ; \ -} while (0) - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-warn", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -static void log_items(pam_handle_t *pamh, const char *function) -{ - const char *service=NULL, *user=NULL, *terminal=NULL, - *rhost=NULL, *ruser=NULL; - - OBTAIN(PAM_SERVICE, service, "<unknown>"); - OBTAIN(PAM_TTY, terminal, "<unknown>"); - OBTAIN(PAM_USER, user, "<unknown>"); - OBTAIN(PAM_RUSER, ruser, "<unknown>"); - OBTAIN(PAM_RHOST, rhost, "<unknown>"); - - _pam_log(LOG_NOTICE, "function=[%s] service=[%s] terminal=[%s] user=[%s]" - " ruser=[%s] rhost=[%s]\n", - function, service, terminal, user, ruser, rhost); -} - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -/* password updating functions */ - -PAM_EXTERN -int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -PAM_EXTERN int -pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -PAM_EXTERN int -pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -PAM_EXTERN int -pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - log_items(pamh, __FUNCTION__); - return PAM_IGNORE; -} - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_warn_modstruct = { - "pam_warn", - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok, -}; - -#endif - -/* end of module definition */ diff --git a/modules/pam_wheel/.cvsignore b/modules/pam_wheel/.cvsignore deleted file mode 100644 index 380a834a..00000000 --- a/modules/pam_wheel/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -dynamic diff --git a/modules/pam_wheel/Makefile b/modules/pam_wheel/Makefile deleted file mode 100644 index 66945ff5..00000000 --- a/modules/pam_wheel/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# $Id$ -# -# This Makefile controls a build process of $(TITLE) module for -# Linux-PAM. You should not modify this Makefile (unless you know -# what you are doing!). -# -# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 -# - -include ../../Make.Rules - -TITLE=pam_wheel - -include ../Simple.Rules diff --git a/modules/pam_wheel/README b/modules/pam_wheel/README deleted file mode 100644 index 336bb31e..00000000 --- a/modules/pam_wheel/README +++ /dev/null @@ -1,33 +0,0 @@ - -pam_wheel: - only permit root authentication too members of wheel group - -RECOGNIZED ARGUMENTS: - debug write a message to syslog indicating success or - failure. - - use_uid the check for wheel membership will be done against - the current uid instead of the original one - (useful when jumping with su from one account to - another for example) - - trust the pam_wheel module will return PAM_SUCCESS instead - of PAM_IGNORE if the user is a member of the wheel - group (thus with a little play stacking the modules - the wheel members may be able to su to root without - being prompted for a passwd). - - deny Reverse the sense of the auth operation: if the user - is trying to get UID 0 access and is a member of the - wheel group, deny access (well, kind of nonsense, but - for use in conjunction with 'group' argument... :-) - - group=xxxx Instead of checking the GID 0 group, use the xxxx - group to perform the authentification. - -MODULE SERVICES PROVIDED: - auth _authetication and _setcred (blank) - -AUTHOR: - Cristian Gafton <gafton@sorosis.ro> - diff --git a/modules/pam_wheel/pam_wheel.c b/modules/pam_wheel/pam_wheel.c deleted file mode 100644 index d629819f..00000000 --- a/modules/pam_wheel/pam_wheel.c +++ /dev/null @@ -1,276 +0,0 @@ -/* pam_wheel module */ - -/* - * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 - * See the end of the file for Copyright Information - * - * - * 1.2 - added 'deny' and 'group=' options - * 1.1 - added 'trust' option - * 1.0 - the code is working for at least another person, so... :-) - * 0.1 - use vsyslog instead of vfprintf/syslog in _pam_log - * - return PAM_IGNORE on success (take care of sloppy sysadmins..) - * - use pam_get_user instead of pam_get_item(...,PAM_USER,...) - * - a new arg use_uid to auth the current uid instead of the - * initial (logged in) one. - * 0.0 - first release - * - * TODO: - * - try to use make_remark from pam_unix/support.c - * - consider returning on failure PAM_FAIL_NOW if the user is not - * a wheel member. - */ - -#define _BSD_SOURCE - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/types.h> -#include <pwd.h> -#include <grp.h> - -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH - -#include <security/pam_modules.h> - -/* some syslogging */ - -static void _pam_log(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-Wheel", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} - -/* checks if a user is on a list of members of the GID 0 group */ - -static int is_on_list(char * const *list, const char *member) -{ - while (*list) { - if (strcmp(*list, member) == 0) - return 1; - list++; - } - return 0; -} - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 -#define PAM_USE_UID_ARG 0x0002 -#define PAM_TRUST_ARG 0x0004 -#define PAM_DENY_ARG 0x0010 - -static int _pam_parse(int argc, const char **argv, char *use_group, - size_t group_length) -{ - int ctrl=0; - - memset(use_group, '\0', group_length); - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strcmp(*argv,"use_uid")) - ctrl |= PAM_USE_UID_ARG; - else if (!strcmp(*argv,"trust")) - ctrl |= PAM_TRUST_ARG; - else if (!strcmp(*argv,"deny")) - ctrl |= PAM_DENY_ARG; - else if (!strncmp(*argv,"group=",6)) - strncpy(use_group,*argv+6,group_length-1); - else { - _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - int ctrl; - const char *username; - char *fromsu; - struct passwd *pwd, *tpwd; - struct group *grp; - int retval = PAM_AUTH_ERR; - char use_group[BUFSIZ]; - - /* Init the optional group */ - bzero(use_group,BUFSIZ); - - ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group)); - retval = pam_get_user(pamh, &username, NULL); - if ((retval != PAM_SUCCESS) || (!username)) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_DEBUG,"can not get the username"); - return PAM_SERVICE_ERR; - } - - /* su to a uid 0 account ? */ - pwd = getpwnam(username); - if (!pwd) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"unknown user %s",username); - return PAM_USER_UNKNOWN; - } - - /* Now we know that the username exists, pass on to other modules... - * the call to pam_get_user made this obsolete, so is commented out - * - * pam_set_item(pamh,PAM_USER,(const void *)username); - */ - - /* is this user an UID 0 account ? */ - if(pwd->pw_uid) { - /* no need to check for wheel */ - return PAM_IGNORE; - } - - if (ctrl & PAM_USE_UID_ARG) { - tpwd = getpwuid(getuid()); - if (!tpwd) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"who is running me ?!"); - return PAM_SERVICE_ERR; - } - fromsu = tpwd->pw_name; - } else { - fromsu = getlogin(); - if (!fromsu) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"who is running me ?!"); - return PAM_SERVICE_ERR; - } - } - - if (!use_group[0]) { - if ((grp = getgrnam("wheel")) == NULL) { - grp = getgrgid(0); - } - } else - grp = getgrnam(use_group); - - if (!grp || !grp->gr_mem) { - if (ctrl & PAM_DEBUG_ARG) { - if (!use_group[0]) - _pam_log(LOG_NOTICE,"no members in a GID 0 group"); - else - _pam_log(LOG_NOTICE,"no members in '%s' group",use_group); - } - if (ctrl & PAM_DENY_ARG) - /* if this was meant to deny access to the members - * of this group and the group does not exist, allow - * access - */ - return PAM_IGNORE; - else - return PAM_AUTH_ERR; - } - - if (is_on_list(grp->gr_mem, fromsu)) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'", - (ctrl & PAM_DENY_ARG)?"denied":"granted", - fromsu,username); - if (ctrl & PAM_DENY_ARG) - return PAM_PERM_DENIED; - else - if (ctrl & PAM_TRUST_ARG) - return PAM_SUCCESS; - else - return PAM_IGNORE; - } - - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'", - (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username); - if (ctrl & PAM_DENY_ARG) - return PAM_SUCCESS; - else - return PAM_PERM_DENIED; -} - -PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) -{ - return PAM_SUCCESS; -} - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_wheel_modstruct = { - "pam_wheel", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997 - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/modules/pammodutil/.cvsignore b/modules/pammodutil/.cvsignore deleted file mode 100644 index 7b4d4ba2..00000000 --- a/modules/pammodutil/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -static diff --git a/modules/pammodutil/Makefile b/modules/pammodutil/Makefile deleted file mode 100644 index a97388ef..00000000 --- a/modules/pammodutil/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -# -# $Id$ -# -# - -include ../../Make.Rules - -LIBNAME=libpammodutil - -# --------------------------------------------- - -dummy: all - -# --------------------------------------------- - -CFLAGS += $(PIC) $(STATIC) $(MOREFLAGS) \ - -DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \ - -DLIBPAM_VERSION_MINOR=$(MINOR_REL) - -# all the object files we care about -LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o - -# static library name -LIBSTATIC = $(LIBNAME).a - -SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ)) - -# --------------------------------------------- -## rules - -all: dirs $(LIBSTATIC) ../../Make.Rules - -dirs: - $(MKDIR) static - -static/%.o : %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ - -$(LIBSTATIC): $(SLIBOBJECTS) - ar cr $@ $(SLIBOBJECTS) - $(RANLIB) $@ - -install: - @echo "at this time, we're not installing $(LIBSTATIC)" - -remove: - @echo "at this time, there is nothing to remove" - -clean: - rm -f a.out core *~ static/*.o - rm -f *.a *.o - if [ -d dynamic ]; then rmdir dynamic ; fi - if [ -d static ]; then rmdir static ; fi diff --git a/modules/pammodutil/README b/modules/pammodutil/README deleted file mode 100644 index 241f83a7..00000000 --- a/modules/pammodutil/README +++ /dev/null @@ -1,15 +0,0 @@ -$Id$ - -This is a libarary of routines for use by modules. The routines seem -to have a common use for modules, but are not part of libpam and never -will be. They are also a convenient layer of abstraction for providing -thread-safe functions that may require use of pam_handle_t 'data' -items to make their thread-safeness tied to the use of a single -pam_handle_t per thread. - -Functions provided so far are all listed in - - include/security/_pam_modutil.h - -. - diff --git a/modules/pammodutil/include/security/_pam_modutil.h b/modules/pammodutil/include/security/_pam_modutil.h deleted file mode 100644 index af8a7ae1..00000000 --- a/modules/pammodutil/include/security/_pam_modutil.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _PAM_MODUTIL_H -#define _PAM_MODUTIL_H - -/* - * $Id$ - * - * This file is a list of handy libc wrappers that attempt to provide some - * thread-safe and other convenient functionality to modules in a form that - * is common, but not dynamically linked with yet another dynamic pam - * library extension. - * - * A number of these functions reserve space in a pam_[sg]et_data item. - * In all cases, the name of the item is prefixed with "_pammodutil_*". - * - * On systems that simply can't support thread safe programming, these - * functions don't support it either - sorry. - * - * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> - */ - -#include <pwd.h> -#include <sys/types.h> - -extern struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, - const char *user); - -extern struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, - uid_t uid); - -extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, - int error_status); - -#endif /* _PAM_MODUTIL_H */ diff --git a/modules/pammodutil/modutil_cleanup.c b/modules/pammodutil/modutil_cleanup.c deleted file mode 100644 index e95d6100..00000000 --- a/modules/pammodutil/modutil_cleanup.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * $Id$ - * - * This function provides a common pam_set_data() friendly version of free(). - */ - -#include "pammodutil.h" - -void _pammodutil_cleanup(pam_handle_t *pamh, void *data, int error_status) -{ - if (data) { - /* junk it */ - (void) free(data); - } -} - diff --git a/modules/pammodutil/modutil_getpwnam.c b/modules/pammodutil/modutil_getpwnam.c deleted file mode 100644 index 287dc065..00000000 --- a/modules/pammodutil/modutil_getpwnam.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Id$ - * - * This function provides a thread safer version of getpwnam() for use - * with PAM modules that care about this sort of thing. - * - * XXX - or at least it should provide a thread-safe alternative. - */ - -#include "pammodutil.h" - -#include <pwd.h> -#include <stdlib.h> - -struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user) -{ -#ifdef HAVE_GETPWNAM_R - - void *buffer=NULL; - size_t length = PWD_INITIAL_LENGTH; - - do { - int status; - void *new_buffer; - struct passwd *result = NULL; - - new_buffer = realloc(buffer, sizeof(struct passwd) + length); - if (new_buffer == NULL) { - - D(("out of memory")); - - /* no memory for the user - so delete the memory */ - if (buffer) { - free(buffer); - } - return NULL; - } - buffer = new_buffer; - - /* make the re-entrant call to get the pwd structure */ - status = getpwnam_r(user, buffer, - sizeof(struct passwd) + (char *) buffer, - length, &result); - if (!status && result) { - status = pam_set_data(pamh, "_pammodutil_getpwnam", result, - _pammodutil_cleanup); - if (status == PAM_SUCCESS) { - D(("success")); - return result; - } - - D(("was unable to register the data item [%s]", - pam_strerror(pamh, status))); - - free(buffer); - return NULL; - - } - - length <<= 1; - - } while (length < PWD_ABSURD_PWD_LENGTH); - - D(("pwd structure took %u bytes or so of memory", - length+sizeof(struct passwd))); - - free(buffer); - return NULL; - -#else /* ie. ifndef HAVE_GETPWNAM_R */ - - /* - * Sorry, there does not appear to be a reentrant version of - * getpwnam(). So, we use the standard libc function. - */ - - return getpwnam(user); - -#endif /* def HAVE_GETPWNAM_R */ -} diff --git a/modules/pammodutil/modutil_getpwuid.c b/modules/pammodutil/modutil_getpwuid.c deleted file mode 100644 index e200dd1e..00000000 --- a/modules/pammodutil/modutil_getpwuid.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Id$ - * - * This function provides a thread safer version of getpwuid() for use - * with PAM modules that care about this sort of thing. - * - * XXX - or at least it should provide a thread-safe alternative. - */ - -#include "pammodutil.h" - -#include <pwd.h> -#include <stdlib.h> - -struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) -{ -#ifdef HAVE_GETPWNAM_R - - void *buffer=NULL; - size_t length = PWD_INITIAL_LENGTH; - - do { - int status; - void *new_buffer; - struct passwd *result = NULL; - - new_buffer = realloc(buffer, sizeof(struct passwd) + length); - if (new_buffer == NULL) { - - D(("out of memory")); - - /* no memory for the user - so delete the memory */ - if (buffer) { - free(buffer); - } - return NULL; - } - buffer = new_buffer; - - /* make the re-entrant call to get the pwd structure */ - status = getpwuid_r(uid, buffer, - sizeof(struct passwd) + (char *) buffer, - length, &result); - if (!status && result) { - status = pam_set_data(pamh, "_pammodutil_getpwuid", result, - _pammodutil_cleanup); - if (status == PAM_SUCCESS) { - D(("success")); - return result; - } - - D(("was unable to register the data item [%s]", - pam_strerror(pamh, status))); - - free(buffer); - return NULL; - - } - - length <<= 1; - - } while (length < PWD_ABSURD_PWD_LENGTH); - - D(("pwd structure took %u bytes or so of memory", - length+sizeof(struct passwd))); - - free(buffer); - return NULL; - -#else /* ie. ifndef HAVE_GETPWNAM_R */ - - /* - * Sorry, there does not appear to be a reentrant version of - * getpwnam(). So, we use the standard libc function. - */ - - return getpwuid(uid); - -#endif /* def HAVE_GETPWNAM_R */ -} diff --git a/modules/pammodutil/pammodutil.h b/modules/pammodutil/pammodutil.h deleted file mode 100644 index efcc98e1..00000000 --- a/modules/pammodutil/pammodutil.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PAMMODUTIL_H -#define PAMMODUTIL_H - -/* - * $Id$ - * - * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> - */ - -#include <security/_pam_aconf.h> -#include <security/_pam_macros.h> -#include <security/pam_modules.h> -#include <security/_pam_modutil.h> - -#define PWD_INITIAL_LENGTH 0x100 -#define PWD_ABSURD_PWD_LENGTH 0x1000 - -/* This is a simple cleanup, it just free()s the 'data' memory */ -extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, - int error_status); - -#endif /* PAMMODUTIL_H */ diff --git a/modules/register_static b/modules/register_static deleted file mode 100755 index f3aebb60..00000000 --- a/modules/register_static +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -if [ `basename $PWD` != "modules" ]; then - echo "$0 must be run from the .../modules directory" - exit 1 -fi - -merge_line () -{ - if [ $# != 3 ]; then - echo "usage: merge_line token filename 'new line'" - fi - if [ -f $2 ]; then -# remove any existing entry... - grep -v "$1" $2 > tmp.$2 - rm -f $2 - mv {tmp.,}$2 - fi - cat << EOT >> $2 -$3 -EOT - -} - - -if [ $# -ne 2 ]; then - - cat << EOT 2>&1 -$0: this script takes TWO arguments: - the 'alphanumeric label' of the module and the location of - its object file from the .../modules/ directory -EOT - exit 1 - -else - echo " - *> registering static module: $1 ($2) <* -" - merge_line "$1" _static_module_list "\ -extern struct pam_module _$1_modstruct;" - - merge_line "$1" _static_module_entry " &_$1_modstruct," - if [ -n "$2" ]; then - merge_line "$2" _static_module_objects "../modules/$2" - fi - -fi - -exit 0 diff --git a/pgp.keys.asc b/pgp.keys.asc deleted file mode 100644 index a516c379..00000000 --- a/pgp.keys.asc +++ /dev/null @@ -1,103 +0,0 @@ -Type Bits/KeyID Date User ID -pub 1024/2A398175 1996/11/17 Andrew G. Morgan <morgan@linux.kernel.org> - Andrew G. Morgan <morgan@transmeta.com> - ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: 2.6.3a - -mQCNAzKOhJ4AAAEEAJ9xYnZSD1kYanF+8GUBhHf/gx6hGd8ZNmS5qIC8Qb8rMcTI -+E16nV+FnNRlPRbShITYjq1TPvVK8gTliZf41N9LRQZw0rywRt1NQyhdfKgDWYxB -kSOwK67oDjkzzC56XS2rrGI6K3Rz/VtYElRyuQ6ZyaKTGcgU/TTwrUUqOYF1AAUR -tCpBbmRyZXcgRy4gTW9yZ2FuIDxtb3JnYW5AbGludXgua2VybmVsLm9yZz6JAJUD -BRA2iFK0NPCtRSo5gXUBAalqA/9s3Hx8BUESiC9PpL88KSVe3ENoO0ogAuMDK3vj -k2a17Twxi92Dc/NPXr8ewEKF/h1GiRetLBVPGaSVC+602+2cr5SHqzUzAeyF2Xa6 -VAxCskxkAssTxIW7nyAMWaOB5A/1xm3YChawVQx3XIvbIp+HXHDNr/60COtlGm7I -IcHftbQnQW5kcmV3IEcuIE1vcmdhbiA8bW9yZ2FuQHRyYW5zbWV0YS5jb20+iQCV -AwUQNohVmTTwrUUqOYF1AQEgWwP+K94N0OO+I2A7lnP5Jp7O+kfMJCFxPZOeozrq -O8uKsAs03ekS+kDJ3p2ec65BOzZyweHEu1HtOtdZbXsN3zynLKBwJrvvaHBQpAqv -BrjfNsl9a+NFmfa4fmdPWTzCaG2rmFlaQvZ6FP7QrHXB/1+VlH0gJ90FOgAd3Qyp -4hhW9g8= -=qQJI ------END PGP PUBLIC KEY BLOCK----- - -Type Bits/KeyID Date User ID -pub 1024/4536A8DD 1996/01/28 Michael K. Johnson <johnsonm@redhat.com> - Michael K. Johnson <johnsonm@nigel.vnet.net> ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: 2.6.3a - -mQCNAzEK0l0AAAEEAMWweYcS6ov1RISP6E7lb3vgQOrmhBy6S/8zkuHo92IkQWXm -V9AcMUY/eJPRJH6yI6o1ZKN4InT4uCkSIQOd2C8XyeIK5jFhpmP9DhoucacNL5H7 -oCV4wtFGhUDaDl9VeTtbWLSMESxJ4T/fL/IfkW95/Q2dF7zIDid5aW9FNqjdAAUR -tChNaWNoYWVsIEsuIEpvaG5zb24gPGpvaG5zb25tQHJlZGhhdC5jb20+iQCVAwUQ -MuqeiDTwrUUqOYF1AQEjywP/bCWLybbZSI8plyUSWD3yxwjsE+8BiOPGRu1AARUz -GbVZq9LqPDyjFtH9DqgXULyZtCAk8ebZonH/h/0EnZTi4tiZg3BHKXhIlWQnNz4D -QRdtUEmMNQzi9+3mU99CBGigsrDQnNrnI88ejo/0YY3gdt6752g5HAvY13h9A0ZP -MFWJAJUDBRAxgAouJ3lpb0U2qN0BActVA/9vgBOUheUpLPiIry/+2qqJv+e+LnHw -DgZqROpli9bhJ4wfb1sXPYkFzchR8BUeU0NY6HvAwxEilSNPE1yQoaJuy8POtTuu -aFO4wvuLp0v5LuatXaU8EsncwjrBsWqRB6Dqd+jyq24Pjx0YKNSRJxceiBE8SBDW -HESAhYTYCBLy77QsTWljaGFlbCBLLiBKb2huc29uIDxqb2huc29ubUBuaWdlbC52 -bmV0Lm5ldD6JAJUDBRAxGljWe01Ojay67k0BAf3qA/48N9OvgGk9nNR+Pg6aW3rK -2Dy8t2RQdFGd4b7gBtZeXUAklq9ppYZtS+cXFHoQ8d7K8XBjHh+rgF2oOSBQUrQf -eb8XkKSZQxB7DZVdi1gAsOzSwCrn4TWSSKc28P4Mjuj1Jr2f1FGST1+cGIl7JbhV -kLGjmvOIgs7lS8FE0Hhm/4kAlQMFEDEWclxEcVNogr/H7QEBN1QD/1iY+KYQyOTz -fgaBsx+Bt11kstmOlYhXx23yK2etG0p8XCD2r3aojGOTR/e3o2bLiJo4xe+iMhOM -dvdSzxSPGQ20wX3jGJaRrRiSClFTQbZSelGG0FcOGfM3mL5zeHaXzRcRciK3VDkD -IFzTQ3J5NJVBIVlAkxTMIxho758lR2SjiQCVAwUQMREqFnoDqzGe1QXFAQFdpAP/ -VPPoYO50seo1rLL28AA2PVKqo6BJwj0ZMsC14MDJEKryBbj/E4Ma25uSlzBjj+t9 -rbygoz0XWUQMLh8XPAEps3nE3n8FWROsdlucGzGiDGKVEygLPzCsjR7aGEspN1Y7 -4qOZPxbpGG7B5exOLur4ACY75m6oBh+PN+Q1liCIYXKJAJUDBRAxDpk1iGe2nxKR -G10BAeQjBACmx4DyJacQXxuckDaKMTXa8v2Q7lQpPDyHdn1oAUsx1mrbSL55v2AI -Q0riFWcFRTERpjAToCLgQjK1pKpmJcduiXURj6TPVKd88hYkuCIpn2hIaI7SCkd8 -HZlfFiuaxVN29UbbzHv3C+mseydpkPRrovqmOSuj2xAGFALo6Vl9U4kAlQMFEDEN -eD5EFXDNRmtCiQEBRmoEAJAuyY0F5hbweDOdeAhxLWeiTl9jGwQYDS3T5B5/9ZpC -bJ1yX7Pk2o7LvR9tg/Ji5sfMMvIpH48DNT4kyjmmChFXCUBccwd+33ugdTcYDwLR -Cdt7k9r2yXz1LEH+lVNKOEIhuIq8/sX61hvFR7+qSABthTLrvvynycD5n2pG3F7L -=aGjw ------END PGP PUBLIC KEY BLOCK----- - -Type Bits/KeyID Date User ID -pub 1024/D4F4D901 1997/03/05 Cristian Gafton <gafton@sorosis.ro> - ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: 2.6.3a - -mQCNAzMdU6sAAAEEAKLF73rRJ3RUtl+y4bLUOVOV7ataJ46ZHxDZeGAVi+/suwT9 -Kq7QdaeFc4Xwaq8PVWv7pZ4/qTwHUkdbjBVeLt+KOlprvKuadyAh9aG/SqmKkEvA -hCS3yZDwNmeSLO7VIN5ko1nIwVD4kPJvS3xX6kn6jd4mvv/qGfGvxKXU9NkBAAUR -tCNDcmlzdGlhbiBHYWZ0b24gPGdhZnRvbkBzb3Jvc2lzLnJvPokAlQMFEDMeTlI0 -8K1FKjmBdQEBmgQD/02JxAU6+fiaBKwRIFDdsLYTy8mPgYaoul9RIX450W5D5nY/ -/696F6TfmFUzvnrvTbZUDyLxHB0mnh4SrdKRKo57i7RDrdx3Mqlt/xP4R6nHwFed -yTMvz3KB9tYuWfC1fJp69/VRIkMrw448zKkgqHUnAKxMIHvXnV3M9jd6lXSYiQCV -AwUQMx1Tq/GvxKXU9NkBAQE3/gP/RZMe59OkBWS4whc9c6eac6zwcC/hNc1vyiZ5 -2TEHJ10PgtNtHchD7j3xsDO17/DGEZB23OQiPAeLdqnBr+y2uiSlQfYdpVHBHX3A -uX3onc69LpEHmUAJAVOvfU1scnDtOH/KeVN3nwc6PWLxzLWzXfUbwLNK+LiPMNMV -1qygu+s= -=J4G2 ------END PGP PUBLIC KEY BLOCK----- - -Type Bits/KeyID Date User ID -pub 1024/A5D75B79 1997/03/01 Andrey V. Savochkin <saw@msu.ru> - ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: 2.6.3a - -mQCNAzMYf1MAAAEEAK1S5jgmWnn8IS9mKoSpXu87f2soQhVZ3XdvsBCK2V7BojlU -0+JJrK+2gMH5tavyFsQ6cKch6I4xH54cS4P4tNE9M7OtfoXOxejtp9U9KZio8T0X -gM8qOS4fTQEfmdHSA5ETe5Vv+WPZ+/3SCo5kD1uIUUwppHDgJH+l396l11t5AAUR -tCBBbmRyZXkgVi4gU2F2b2Noa2luIDxzYXdAbXN1LnJ1PokAlQMFEDaIUh008K1F -KjmBdQEBFtkD/38mraXdr4aEYC6lxlG3cF+59XB6FjyBYhtwgNshpI2mB5XLr25p -f4jMFNUqnY/bGjXWKwbNguzJ0ukD8TgOg1ZXQZztRso1t1Y2M1KPbwlqj8ib1bZG -inQO/eqLrVwFH6F9CTiF0Fgy7faAIHN6BfE0o8earrcIwjT7sxRej3lziQCVAwUQ -M35653fqPT1smcpJAQHeqgQAlXMOru6Rz1TkslVrWD0n7dvBUHQxs0HS1pcWJnZJ -6kcYMLSA2RBi1fRabwzuOtzK60tOmfmnD7btcGBMMflOtfSulEg/xKNw2awEsNQK -ULEIBsvrpMr0UN4hWkxTggDXaykg7rQqgrbAsicoLuTtPDIbc+yhQcFEVGJiPO/I -tqiJAJUDBRAzfnUef89/VVw/1FkBAQ2lA/9q6FQM4RZzp75qxZ7jqAwUy9RFAKhp -L63YFJX3i1JsUjNoO51pjj5pEAxVVQsorqbdsmpC2aOUTf1AufEcs1kLojb3tc19 -MhXPyHTJs66QqWutdP/yOW+CLzmILAsbEgI6O+toVZ0rHVXjEtRgKUnYReHLrlYj -RKlBnkVc3NtPcIkAlQMFEDMYf1N/pd/epddbeQEBfKYD/3x/PkH2e+Cy7YXsfwxb -y/n+6eNIbfakSYjkwN5tDOeaKhdQKUJBKVwAzD2yrLmMDx6uW+FUOTucb6Anau6R -iKrAJq/a4DcpAeymo7cAthVU7en7HWwebQcL4wZGao1BJI+ulynki4sIqkfbGP83 -DK775eovl5X195ZkE/wNJvoi -=V5TY ------END PGP PUBLIC KEY BLOCK----- -- cgit v1.2.3