summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/openssh/sshlogin.c137
-rw-r--r--crypto/openssl/crypto/uid.c88
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_load_verify_locations.pod124
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_sess_number.pod76
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_sess_set_cache_size.pod51
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_sessions.pod34
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod90
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_set_mode.pod78
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_set_options.pod183
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_set_session_cache_mode.pod107
-rw-r--r--crypto/openssl/doc/ssl/SSL_CTX_use_certificate.pod154
-rw-r--r--crypto/openssl/doc/ssl/SSL_get_client_CA_list.pod52
-rw-r--r--crypto/openssl/doc/ssl/SSL_get_version.pod46
-rw-r--r--crypto/openssl/doc/ssl/SSL_set_connect_state.pod47
-rw-r--r--crypto/openssl/doc/ssl/SSL_set_shutdown.pod68
-rw-r--r--crypto/openssl/doc/ssl/d2i_SSL_SESSION.pod56
-rwxr-xr-xcrypto/openssl/test/bctest96
-rw-r--r--lib/libc/gen/getprogname.392
-rw-r--r--lib/libc/gen/getprogname.c13
-rw-r--r--lib/libc/gen/setprogname.c13
-rw-r--r--lib/libc/stdlib/hcreate.c184
-rw-r--r--lib/libc/string/wmemchr.3145
-rw-r--r--lib/libc_r/test/join_leak_d.c108
-rw-r--r--lib/libc_r/test/join_leak_d.exp2
-rw-r--r--lib/libpam/modules/pam_krb5/COPYRIGHT195
-rw-r--r--lib/libpam/modules/pam_krb5/README72
-rw-r--r--lib/libpam/modules/pam_krb5/TODO16
-rw-r--r--lib/libpam/modules/pam_krb5/compat_heimdal.c141
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.8191
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.h23
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_acct.c83
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_auth.c505
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_pass.c200
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_sess.c28
-rw-r--r--lib/libpam/modules/pam_krb5/support.c185
-rw-r--r--release/doc/share/sgml/release.dsl38
-rw-r--r--share/mk/bsd.sys.mk39
-rw-r--r--share/monetdef/sk_SK.ISO8859-2.src38
-rw-r--r--share/numericdef/sk_SK.ISO8859-2.src14
-rw-r--r--share/timedef/sk_SK.ISO8859-2.src105
-rw-r--r--sys/fs/smbfs/smbfs_vfsops.c500
-rw-r--r--sys/netsmb/smb_trantcp.c690
-rw-r--r--sys/pccard/mecia.c730
-rw-r--r--sys/pccard/meciareg.h60
44 files changed, 5897 insertions, 0 deletions
diff --git a/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c
new file mode 100644
index 000000000000..b8536c0bcbcf
--- /dev/null
+++ b/crypto/openssh/sshlogin.c
@@ -0,0 +1,137 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * This file performs some of the things login(1) normally does. We cannot
+ * easily use something like login -p -h host -f user, because there are
+ * several different logins around, and it is hard to determined what kind of
+ * login the current system has. Also, we want to be able to execute commands
+ * on a tty.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 1999 Theo de Raadt. All rights reserved.
+ * Copyright (c) 1999 Markus Friedl. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 "includes.h"
+RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $");
+RCSID("$FreeBSD$");
+
+#include <libutil.h>
+#include <utmp.h>
+#include "sshlogin.h"
+#include "log.h"
+
+/*
+ * Returns the time when the user last logged in. Returns 0 if the
+ * information is not available. This must be called before record_login.
+ * The host the user logged in from will be returned in buf.
+ */
+
+u_long
+get_last_login_time(uid_t uid, const char *logname,
+ char *buf, u_int bufsize)
+{
+ struct lastlog ll;
+ char *lastlog;
+ int fd;
+
+ lastlog = _PATH_LASTLOG;
+ buf[0] = '\0';
+
+ fd = open(lastlog, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
+ if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ if (bufsize > sizeof(ll.ll_host) + 1)
+ bufsize = sizeof(ll.ll_host) + 1;
+ strncpy(buf, ll.ll_host, bufsize - 1);
+ buf[bufsize - 1] = 0;
+ return ll.ll_time;
+}
+
+/*
+ * Records that the user has logged in. I these parts of operating systems
+ * were more standardized.
+ */
+
+void
+record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
+ const char *host, struct sockaddr * addr)
+{
+ int fd;
+ struct lastlog ll;
+ char *lastlog;
+ struct utmp u;
+
+ /* Construct an utmp/wtmp entry. */
+ memset(&u, 0, sizeof(u));
+ strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
+ u.ut_time = time(NULL);
+ strncpy(u.ut_name, user, sizeof(u.ut_name));
+ realhostname_sa(u.ut_host, sizeof(u.ut_host), addr, addr->sa_len);
+
+ login(&u);
+ lastlog = _PATH_LASTLOG;
+
+ /* Update lastlog unless actually recording a logout. */
+ if (strcmp(user, "") != 0) {
+ /*
+ * It is safer to bzero the lastlog structure first because
+ * some systems might have some extra fields in it (e.g. SGI)
+ */
+ memset(&ll, 0, sizeof(ll));
+
+ /* Update lastlog. */
+ ll.ll_time = time(NULL);
+ strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
+ strncpy(ll.ll_host, host, sizeof(ll.ll_host));
+ fd = open(lastlog, O_RDWR);
+ if (fd >= 0) {
+ lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
+ if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
+ log("Could not write %.100s: %.100s", lastlog, strerror(errno));
+ close(fd);
+ }
+ }
+}
+
+/* Records that the user has logged out. */
+
+void
+record_logout(pid_t pid, const char *ttyname)
+{
+ const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
+ if (logout(line))
+ logwtmp(line, "", "");
+}
diff --git a/crypto/openssl/crypto/uid.c b/crypto/openssl/crypto/uid.c
new file mode 100644
index 000000000000..b5b61b76d4e3
--- /dev/null
+++ b/crypto/openssl/crypto/uid.c
@@ -0,0 +1,88 @@
+/* crypto/uid.c */
+/* ====================================================================
+ * Copyright (c) 2001 The OpenSSL Project. 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 acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/crypto.h>
+
+#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ > 2)
+
+#include <unistd.h>
+
+int OPENSSL_issetugid(void)
+ {
+ return issetugid();
+ }
+
+#elif defined(WIN32)
+
+int OPENSSL_issetugid(void)
+ {
+ return 0;
+ }
+
+#else
+
+#include <unistd.h>
+#include <sys/types.h>
+
+int OPENSSL_issetugid(void)
+ {
+ if (getuid() != geteuid()) return 1;
+ if (getgid() != getegid()) return 1;
+ return 0;
+ }
+#endif
+
+
+
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_load_verify_locations.pod b/crypto/openssl/doc/ssl/SSL_CTX_load_verify_locations.pod
new file mode 100644
index 000000000000..88f18bd5ff40
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_load_verify_locations.pod
@@ -0,0 +1,124 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_load_verify_locations - set default locations for trusted CA
+certificates
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+ const char *CApath);
+
+=head1 DESCRIPTION
+
+SSL_CTX_load_verify_locations() specifies the locations for B<ctx>, at
+which CA certificates for verification purposes are located. The certificates
+available via B<CAfile> and B<CApath> are trusted.
+
+=head1 NOTES
+
+If B<CAfile> is not NULL, it points to a file of CA certificates in PEM
+format. The file can contain several CA certificates identified by
+
+ -----BEGIN CERTIFICATE-----
+ ... (CA certificate in base64 encoding) ...
+ -----END CERTIFICATE-----
+
+sequences. Before, between, and after the certificates text is allowed
+which can be used e.g. for descriptions of the certificates.
+
+The B<CAfile> is processed on execution of the SSL_CTX_load_verify_locations()
+function.
+
+If on an TLS/SSL server no special setting is performed using *client_CA_list()
+functions, the certificates contained in B<CAfile> are listed to the client
+as available CAs during the TLS/SSL handshake.
+
+If B<CApath> is not NULL, it points to a directory containing CA certificates
+in PEM format. The files each contain one CA certificate. The files are
+looked up by the CA subject name hash value, which must hence be available.
+If more than one CA certificate with the same name hash value exist, the
+extension must be different (e.g. 9d66eef0.0, 9d66eef0.1 etc). The search
+is performed in the ordering of the extension number, regardless of other
+properties of the certificates.
+Use the B<c_rehash> utility to create the necessary links.
+
+The certificates in B<CApath> are only looked up when required, e.g. when
+building the certificate chain or when actually performing the verification
+of a peer certificate.
+
+On a server, the certificates in B<CApath> are not listed as available
+CA certificates to a client during a TLS/SSL handshake.
+
+When looking up CA certificates, the OpenSSL library will first search the
+certificates in B<CAfile>, then those in B<CApath>. Certificate matching
+is done based on the subject name, the key identifier (if present), and the
+serial number as taken from the certificate to be verified. If these data
+do not match, the next certificate will be tried. If a first certificate
+matching the parameters is found, the verification process will be performed;
+no other certificates for the same parameters will be searched in case of
+failure.
+
+When building its own certificate chain, an OpenSSL client/server will
+try to fill in missing certificates from B<CAfile>/B<CApath>, if the
+certificate chain was not explicitly specified (see
+L<SSL_CTX_add_extra_chain_cert(3)|SSL_CTX_add_extra_chain_cert(3)>,
+L<SSL_CTX_use_certificate(3)|SSL_CTX_use_certificate(3)>.
+
+=head1 WARNINGS
+
+If several CA certificates matching the name, key identifier, and serial
+number condition are available, only the first one will be examined. This
+may lead to unexpected results if the same CA certificate is available
+with different expiration dates. If a "certificate expired" verification
+error occurs, no other certificate will be searched. Make sure to not
+have expired certificates mixed with valid ones.
+
+=head1 EXAMPLES
+
+Generate a CA certificate file with descriptive text from the CA certificates
+ca1.pem ca2.pem ca3.pem:
+
+ #!/bin/sh
+ rm CAfile.pem
+ for i in ca1.pem ca2.pem ca3.pem ; do
+ openssl x509 -in $i -text >> CAfile.pem
+ done
+
+Prepare the directory /some/where/certs containing several CA certificates
+for use as B<CApath>:
+
+ cd /some/where/certs
+ c_rehash .
+
+=head1 RETURN VALUES
+
+The following return values can occur:
+
+=over 4
+
+=item 0
+
+The operation failed because B<CAfile> and B<CApath> are NULL or the
+processing at one of the locations specified failed. Check the error
+stack to find out the reason.
+
+=item 1
+
+The operation succeeded.
+
+=back
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>,
+L<SSL_CTX_set_client_CA_list(3)|SSL_CTX_set_client_CA_list(3)>,
+L<SSL_get_client_CA_list(3)|SSL_get_client_CA_list(3)>,
+L<SSL_CTX_use_certificate(3)|SSL_CTX_use_certificate(3)>,
+L<SSL_CTX_add_extra_chain_cert(3)|SSL_CTX_add_extra_chain_cert(3)>
+
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_sess_number.pod b/crypto/openssl/doc/ssl/SSL_CTX_sess_number.pod
new file mode 100644
index 000000000000..19aa4e29027b
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_sess_number.pod
@@ -0,0 +1,76 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_sess_number, SSL_CTX_sess_connect, SSL_CTX_sess_connect_good, SSL_CTX_sess_connect_renegotiate, SSL_CTX_sess_accept, SSL_CTX_sess_accept_good, SSL_CTX_sess_accept_renegotiate, SSL_CTX_sess_hits, SSL_CTX_sess_cb_hits, SSL_CTX_sess_misses, SSL_CTX_sess_timeouts, SSL_CTX_sess_cache_full - obtain session cache statistics
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ long SSL_CTX_sess_number(SSL_CTX *ctx);
+ long SSL_CTX_sess_connect(SSL_CTX *ctx);
+ long SSL_CTX_sess_connect_good(SSL_CTX *ctx);
+ long SSL_CTX_sess_connect_renegotiate(SSL_CTX *ctx);
+ long SSL_CTX_sess_accept(SSL_CTX *ctx);
+ long SSL_CTX_sess_accept_good(SSL_CTX *ctx);
+ long SSL_CTX_sess_accept_renegotiate(SSL_CTX *ctx);
+ long SSL_CTX_sess_hits(SSL_CTX *ctx);
+ long SSL_CTX_sess_cb_hits(SSL_CTX *ctx);
+ long SSL_CTX_sess_misses(SSL_CTX *ctx);
+ long SSL_CTX_sess_timeouts(SSL_CTX *ctx);
+ long SSL_CTX_sess_cache_full(SSL_CTX *ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_sess_number() returns the current number of sessions in the internal
+session cache.
+
+SSL_CTX_sess_connect() returns the number of started SSL/TLS handshakes in
+client mode.
+
+SSL_CTX_sess_connect_good() returns the number of successfully established
+SSL/TLS sessions in client mode.
+
+SSL_CTX_sess_connect_renegotiate() returns the number of start renegotiations
+in client mode.
+
+SSL_CTX_sess_accept() returns the number of started SSL/TLS handshakes in
+server mode.
+
+SSL_CTX_sess_accept_good() returns the number of successfully established
+SSL/TLS sessions in server mode.
+
+SSL_CTX_sess_accept_renegotiate() returns the number of start renegotiations
+in server mode.
+
+SSL_CTX_sess_hits() returns the number of successfully reused sessions.
+In client mode a session set with L<SSL_set_session(3)|SSL_set_session(3)>
+successfully reused is counted as a hit. In server mode a session successfully
+retrieved from internal or external cache is counted as a hit.
+
+SSL_CTX_sess_cb_hits() returns the number of successfully retrieved sessions
+from the external session cache in server mode.
+
+SSL_CTX_sess_misses() returns the number of sessions proposed by clients
+that were not found in the internal session cache in server mode.
+
+SSL_CTX_sess_timeouts() returns the number of sessions proposed by clients
+and either found in the internal or external session cache in server mode,
+ but that were invalid due to timeout. These sessions are not included in
+the SSL_CTX_sess_hits() count.
+
+SSL_CTX_sess_cache_full() returns the number of sessions that were removed
+because the maximum session cache size was exceeded.
+
+=head1 RETURN VALUES
+
+The functions return the values indicated in the DESCRIPTION section.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_set_session(3)|SSL_set_session(3)>,
+L<SSL_CTX_set_session_cache_mode(3)|SSL_CTX_set_session_cache_mode(3)>
+L<SSL_CTX_sess_set_cache_size(3)|SSL_CTX_sess_set_cache_size(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_sess_set_cache_size.pod b/crypto/openssl/doc/ssl/SSL_CTX_sess_set_cache_size.pod
new file mode 100644
index 000000000000..d59a7db636a8
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_sess_set_cache_size.pod
@@ -0,0 +1,51 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_sess_set_cache_size, SSL_CTX_sess_get_cache_size - manipulate session cache size
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, long t);
+ long SSL_CTX_sess_get_cache_size(SSL_CTX *ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_sess_set_cache_size() sets the size of the internal session cache
+of context B<ctx> to B<t>.
+
+SSL_CTX_sess_get_cache_size() returns the currently valid session cache size.
+
+=head1 NOTES
+
+The internal session cache size is SSL_SESSION_CACHE_MAX_SIZE_DEFAULT,
+currently 1024*20, so that up to 20000 sessions can be held. This size
+can be modified using the SSL_CTX_sess_set_cache_size() call. A special
+case is the size 0, which is used for unlimited size.
+
+When the maximum number of sessions is reached, no more new sessions are
+added to the cache. New space may be added by calling
+L<SSL_CTX_flush_sessions(3)|<SSL_CTX_flush_sessions(3)> to remove
+expired sessions.
+
+If the size of the session cache is reduced and more sessions are already
+in the session cache, old session will be removed at the next time a
+session shall be added. This removal is not synchronized with the
+expiration of sessions.
+
+=head1 RETURN VALUES
+
+SSL_CTX_sess_set_cache_size() returns the previously valid size.
+
+SSL_CTX_sess_get_cache_size() returns the currently valid size.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>,
+L<SSL_CTX_set_session_cache_mode(3)|SSL_CTX_set_session_cache_mode(3)>,
+L<SSL_CTX_sess_number(3)|SSL_CTX_sess_number(3)>,
+L<SSL_CTX_flush_sessions(3)|<SSL_CTX_flush_sessions(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_sessions.pod b/crypto/openssl/doc/ssl/SSL_CTX_sessions.pod
new file mode 100644
index 000000000000..e05aab3c1bc2
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_sessions.pod
@@ -0,0 +1,34 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_sessions - access internal session cache
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_sessions() returns a pointer to the lhash databases containing the
+internal session cache for B<ctx>.
+
+=head1 NOTES
+
+The sessions in the internal session cache are kept in an
+L<lhash(3)|lhash(3)> type database. It is possible to directly
+access this database e.g. for searching. In parallel, the sessions
+form a linked list which is maintained separately from the
+L<lhash(3)|lhash(3)> operations, so that the database must not be
+modified directly but by using the
+L<SSL_CTX_add_session(3)|SSL_CTX_add_session(3)> family of functions.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<lhash(3)|lhash(3)>,
+L<SSL_CTX_add_session(3)|SSL_CTX_add_session(3)>,
+L<SSL_CTX_set_session_cache_mode(3)|SSL_CTX_set_session_cache_mode(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod b/crypto/openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod
new file mode 100644
index 000000000000..81e312761e7a
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod
@@ -0,0 +1,90 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_client_CA_list, SSL_set_client_CA_list, SSL_CTX_add_client_CA,
+SSL_add_client_CA - set list of CAs sent to the client when requesting a
+client certificate
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *list);
+ void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *list);
+ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *cacert);
+ int SSL_add_client_CA(SSL *ssl, X509 *cacert);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_client_CA_list() sets the B<list> of CAs sent to the client when
+requesting a client certificate for B<ctx>.
+
+SSL_set_client_CA_list() sets the B<list> of CAs sent to the client when
+requesting a client certificate for the chosen B<ssl>, overriding the
+setting valid for B<ssl>'s SSL_CTX object.
+
+SSL_CTX_add_client_CA() adds the CA name extracted from B<cacert> to the
+list of CAs sent to the client when requesting a client certificate for
+B<ctx>.
+
+SSL_add_client_CA() adds the CA name extracted from B<cacert> to the
+list of CAs sent to the client when requesting a client certificate for
+the chosen B<ssl>, overriding the setting valid for B<ssl>'s SSL_CTX object.
+
+=head1 NOTES
+
+When a TLS/SSL server requests a client certificate (see
+B<SSL_CTX_set_verify_options()>), it sends a list of CAs, for which
+it will accept certificates, to the client. If no special list is provided,
+the CAs available using the B<CAfile> option in
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>
+are sent.
+
+This list can be explicitly set using the SSL_CTX_set_client_CA_list() for
+B<ctx> and SSL_set_client_CA_list() for the specific B<ssl>. The list
+specified overrides the previous setting. The CAs listed do not become
+trusted (B<list> only contains the names, not the complete certificates); use
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>
+to additionally load them for verification.
+
+SSL_CTX_add_client_CA() and SSL_add_client_CA() can be used to add additional
+items the list of client CAs. If no list was specified before using
+SSL_CTX_set_client_CA_list() or SSL_set_client_CA_list(), a new client
+CA list for B<ctx> or B<ssl> (as appropriate) is opened. The CAs implicitly
+specified using
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>
+are no longer used automatically.
+
+These functions are only useful for TLS/SSL servers.
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_client_CA_list() and SSL_set_client_CA_list() do not return
+diagnostic information.
+
+SSL_CTX_add_client_CA() and SSL_add_client_CA() have the following return
+values:
+
+=over 4
+
+=item 1
+
+The operation succeeded.
+
+=item 0
+
+A failure while manipulating the STACK_OF(X509_NAME) object occurred or
+the X509_NAME could not be extracted from B<cacert>. Check the error stack
+to find out the reason.
+
+=back
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>,
+L<SSL_get_client_CA_list(3)|SSL_get_client_CA_list(3)>,
+L<SSL_load_client_CA_file(3)|SSL_load_client_CA_file(3)>
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_set_mode.pod b/crypto/openssl/doc/ssl/SSL_CTX_set_mode.pod
new file mode 100644
index 000000000000..9a035bb4d184
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_set_mode.pod
@@ -0,0 +1,78 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_mode, SSL_set_mode, SSL_CTX_get_mode, SSL_get_mode - manipulate SSL engine mode
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ long SSL_CTX_set_mode(SSL_CTX *ctx, long mode);
+ long SSL_set_mode(SSL *ssl, long mode);
+
+ long SSL_CTX_get_mode(SSL_CTX *ctx);
+ long SSL_get_mode(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_mode() adds the mode set via bitmask in B<mode> to B<ctx>.
+Options already set before are not cleared.
+
+SSL_set_mode() adds the mode set via bitmask in B<mode> to B<ssl>.
+Options already set before are not cleared.
+
+SSL_CTX_get_mode() returns the mode set for B<ctx>.
+
+SSL_get_mode() returns the mode set for B<ssl>.
+
+=head1 NOTES
+
+The following mode changes are available:
+
+=over 4
+
+=item SSL_MODE_ENABLE_PARTIAL_WRITE
+
+Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
+when just a single record has been written). When not set (the default),
+SSL_write() will only report success once the complete chunk was written.
+
+=item SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
+
+Make it possible to retry SSL_write() with changed buffer location
+(the buffer contents must stay the same). This is not the default to avoid
+the misconception that non-blocking SSL_write() behaves like
+non-blocking write().
+
+=item SSL_MODE_AUTO_RETRY
+
+Never bother the application with retries if the transport is blocking.
+If a renegotiation take place during normal operation, a
+L<SSL_read(3)|SSL_read(3)> or L<SSL_write(3)|SSL_write(3)> would return
+with -1 and indicate the need to retry with SSL_ERROR_WANT_READ.
+In a non-blocking environment applications must be prepared to handle
+incomplete read/write operations.
+In a blocking environment, applications are not always prepared to
+deal with read/write operations returning without success report. The
+flag SSL_MODE_AUTO_RETRY will cause read/write operations to only
+return after the handshake and successful completion.
+
+=back
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_mode() and SSL_set_mode() return the new mode bitmask
+after adding B<mode>.
+
+SSL_CTX_get_mode() and SSL_get_mode() return the current bitmask.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_read(3)|SSL_read(3)>, L<SSL_write(3)|SSL_write(3)>
+
+=head1 HISTORY
+
+SSL_MODE_AUTO_RETRY as been added in OpenSSL 0.9.6.
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_set_options.pod b/crypto/openssl/doc/ssl/SSL_CTX_set_options.pod
new file mode 100644
index 000000000000..3dc7cc74ad63
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_set_options.pod
@@ -0,0 +1,183 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_options, SSL_set_options, SSL_CTX_get_options, SSL_get_options - manipulate SSL engine options
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ long SSL_CTX_set_options(SSL_CTX *ctx, long options);
+ long SSL_set_options(SSL *ssl, long options);
+
+ long SSL_CTX_get_options(SSL_CTX *ctx);
+ long SSL_get_options(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_options() adds the options set via bitmask in B<options> to B<ctx>.
+Options already set before are not cleared.
+
+SSL_set_options() adds the options set via bitmask in B<options> to B<ssl>.
+Options already set before are not cleared.
+
+SSL_CTX_get_options() returns the options set for B<ctx>.
+
+SSL_get_options() returns the options set for B<ssl>.
+
+=head1 NOTES
+
+The behaviour of the SSL library can be changed by setting several options.
+The options are coded as bitmasks and can be combined by a logical B<or>
+operation (|). Options can only be added but can never be reset.
+
+During a handshake, the option settings of the SSL object used. When
+a new SSL object is created from a context using SSL_new(), the current
+option setting is copied. Changes to B<ctx> do not affect already created
+SSL objects. SSL_clear() does not affect the settings.
+
+The following B<bug workaround> options are available:
+
+=over 4
+
+=item SSL_OP_MICROSOFT_SESS_ID_BUG
+
+www.microsoft.com - when talking SSLv2, if session-id reuse is
+performed, the session-id passed back in the server-finished message
+is different from the one decided upon.
+
+=item SSL_OP_NETSCAPE_CHALLENGE_BUG
+
+Netscape-Commerce/1.12, when talking SSLv2, accepts a 32 byte
+challenge but then appears to only use 16 bytes when generating the
+encryption keys. Using 16 bytes is ok but it should be ok to use 32.
+According to the SSLv3 spec, one should use 32 bytes for the challenge
+when operating in SSLv2/v3 compatibility mode, but as mentioned above,
+this breaks this server so 16 bytes is the way to go.
+
+=item SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+
+ssl3.netscape.com:443, first a connection is established with RC4-MD5.
+If it is then resumed, we end up using DES-CBC3-SHA. It should be
+RC4-MD5 according to 7.6.1.3, 'cipher_suite'.
+
+Netscape-Enterprise/2.01 (https://merchant.netscape.com) has this bug.
+It only really shows up when connecting via SSLv2/v3 then reconnecting
+via SSLv3. The cipher list changes....
+
+NEW INFORMATION. Try connecting with a cipher list of just
+DES-CBC-SHA:RC4-MD5. For some weird reason, each new connection uses
+RC4-MD5, but a re-connect tries to use DES-CBC-SHA. So netscape, when
+doing a re-connect, always takes the first cipher in the cipher list.
+
+=item SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+
+...
+
+=item SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+
+...
+
+=item SSL_OP_MSIE_SSLV2_RSA_PADDING
+
+...
+
+=item SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+
+...
+
+=item SSL_OP_TLS_D5_BUG
+
+...
+
+=item SSL_OP_TLS_BLOCK_PADDING_BUG
+
+...
+
+=item SSL_OP_TLS_ROLLBACK_BUG
+
+Disable version rollback attack detection.
+
+During the client key exchange, the client must send the same information
+about acceptable SSL/TLS protocol levels as during the first hello. Some
+clients violate this rule by adapting to the server's answer. (Example:
+the client sends a SSLv2 hello and accepts up to SSLv3.1=TLSv1, the server
+only understands up to SSLv3. In this case the client must still use the
+same SSLv3.1=TLSv1 announcement. Some clients step down to SSLv3 with respect
+to the server's answer and violate the version rollback protection.)
+
+=item SSL_OP_ALL
+
+All of the above bug workarounds.
+
+=back
+
+It is save and recommended to use SSL_OP_ALL to enable the bug workaround
+options.
+
+The following B<modifying> options are available:
+
+=over 4
+
+=item SSL_OP_SINGLE_DH_USE
+
+Always create a new key when using temporary DH parameters.
+
+=item SSL_OP_EPHEMERAL_RSA
+
+Also use the temporary RSA key when doing RSA operations.
+
+=item SSL_OP_PKCS1_CHECK_1
+
+...
+
+=item SSL_OP_PKCS1_CHECK_2
+
+...
+
+=item SSL_OP_NETSCAPE_CA_DN_BUG
+
+If we accept a netscape connection, demand a client cert, have a
+non-self-sighed CA which does not have it's CA in netscape, and the
+browser has a cert, it will crash/hang. Works for 3.x and 4.xbeta
+
+=item SSL_OP_NON_EXPORT_FIRST
+
+On servers try to use non-export (stronger) ciphers first. This option does
+not work under all circumstances (in the code it is declared "broken").
+
+=item SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
+
+...
+
+=item SSL_OP_NO_SSLv2
+
+Do not use the SSLv2 protocol.
+
+=item SSL_OP_NO_SSLv3
+
+Do not use the SSLv3 protocol.
+
+=item SSL_OP_NO_TLSv1
+
+Do not use the TLSv1 protocol.
+
+=back
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_options() and SSL_set_options() return the new options bitmask
+after adding B<options>.
+
+SSL_CTX_get_options() and SSL_get_options() return the current bitmask.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_new(3)|SSL_new(3)>, L<SSL_clear(3)|SSL_clear(3)>
+
+=head1 HISTORY
+
+SSL_OP_TLS_ROLLBACK_BUG has been added in OpenSSL 0.9.6.
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_set_session_cache_mode.pod b/crypto/openssl/doc/ssl/SSL_CTX_set_session_cache_mode.pod
new file mode 100644
index 000000000000..083766f8d084
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_set_session_cache_mode.pod
@@ -0,0 +1,107 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_session_cache_mode, SSL_CTX_get_session_cache_mode - enable/disable session caching
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ long SSL_CTX_set_session_cache_mode(SSL_CTX ctx, long mode);
+ long SSL_CTX_get_session_cache_mode(SSL_CTX ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_session_cache_mode() enables/disables session caching
+by setting the operational mode for B<ctx> to <mode>.
+
+SSL_CTX_get_session_cache_mode() returns the currently used cache mode.
+
+=head1 NOTES
+
+The OpenSSL library can store/retrieve SSL/TLS sessions for later reuse.
+The sessions can be held in memory for each B<ctx>, if more than one
+SSL_CTX object is being maintained, the sessions are unique for each SSL_CTX
+object.
+
+In order to reuse a session, a client must send the session's id to the
+server. It can only send exactly one id. The server then decides whether it
+agrees in reusing the session or starts the handshake for a new session.
+
+A server will lookup up the session in its internal session storage. If
+the session is not found in internal storage or internal storage is
+deactivated, the server will try the external storage if available.
+
+Since a client may try to reuse a session intended for use in a different
+context, the session id context must be set by the server (see
+L<SSL_CTX_set_session_id_context(3)|SSL_CTX_set_session_id_context(3)>).
+
+The following session cache modes and modifiers are available:
+
+=over 4
+
+=item SSL_SESS_CACHE_OFF
+
+No session caching for client or server takes place.
+
+=item SSL_SESS_CACHE_CLIENT
+
+Client sessions are added to the session cache. As there is no reliable way
+for the OpenSSL library to know whether a session should be reused or which
+session to choose (due to the abstract BIO layer the SSL engine does not
+have details about the connection), the application must select the session
+to be reused by using the L<SSL_set_session(3)|SSL_set_session(3)>
+function. This option is not activated by default.
+
+=item SSL_SESS_CACHE_SERVER
+
+Server sessions are added to the session cache. When a client proposes a
+session to be reused, the session is looked up in the internal session cache.
+If the session is found, the server will try to reuse the session.
+This is the default.
+
+=item SSL_SESS_CACHE_BOTH
+
+Enable both SSL_SESS_CACHE_CLIENT and SSL_SESS_CACHE_SERVER at the same time.
+
+=item SSL_SESS_CACHE_NO_AUTO_CLEAR
+
+Normally the session cache is checked for expired sessions every
+255 connections using the
+L<SSL_CTX_flush_sessions(3)|SSL_CTX_flush_sessions(3)> function. Since
+this may lead to a delay which cannot be controlled, the automatic
+flushing may be disabled and
+L<SSL_CTX_flush_sessions(3)|SSL_CTX_flush_sessions(3)> can be called
+explicitly by the application.
+
+=item SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
+
+By setting this flag sessions are cached in the internal storage but
+they are not looked up automatically. If an external session cache
+is enabled, sessions are looked up in the external cache. As automatic
+lookup only applies for SSL/TLS servers, the flag has no effect on
+clients.
+
+=back
+
+The default mode is SSL_SESS_CACHE_SERVER.
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_session_cache_mode() returns the previously set cache mode.
+
+SSL_CTX_get_session_cache_mode() returns the currently set cache mode.
+
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_set_session(3)|SSL_set_session(3)>,
+L<SSL_CTX_sess_number(3)|SSL_CTX_sess_number(3)>,
+L<SSL_CTX_sess_set_cache_size(3)|SSL_CTX_sess_set_cache_size(3)>,
+L<SSL_CTX_sess_set_get_cb(3)|SSL_CTX_sess_set_get_cb(3)>,
+L<SSL_CTX_set_session_id_context(3)|SSL_CTX_set_session_id_context(3)>,
+L<SSL_CTX_set_timeout.pod(3)|SSL_CTX_set_timeout.pod(3)>,
+L<SSL_CTX_flush_sessions(3)|SSL_CTX_flush_sessions(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_CTX_use_certificate.pod b/crypto/openssl/doc/ssl/SSL_CTX_use_certificate.pod
new file mode 100644
index 000000000000..3b2fe6fc5081
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_CTX_use_certificate.pod
@@ -0,0 +1,154 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_use_certificate, SSL_CTX_use_certificate_ASN1, SSL_CTX_use_certificate_file, SSL_use_certificate, SSL_use_certificate_ASN1, SSL_use_certificate_file, SSL_CTX_use_certificate_chain_file, SSL_CTX_use_PrivateKey, SSL_CTX_use_PrivateKey_ASN1, SSL_CTX_use_PrivateKey_file, SSL_CTX_use_RSAPrivateKey, SSL_CTX_use_RSAPrivateKey_ASN1, SSL_CTX_use_RSAPrivateKey_file, SSL_use_PrivateKey_file, SSL_use_PrivateKey_ASN1, SSL_use_PrivateKey, SSL_use_RSAPrivateKey, SSL_use_RSAPrivateKey_ASN1, SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key - load certificate and key data
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
+ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d);
+ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
+ int SSL_use_certificate(SSL *ssl, X509 *x);
+ int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len);
+ int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
+
+ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
+
+ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
+ int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d,
+ long len);
+ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
+ int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len);
+ int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
+ int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, unsigned char *d, long len);
+ int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
+ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
+ int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
+ int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
+
+ int SSL_CTX_check_private_key(SSL_CTX *ctx);
+ int SSL_check_private_key(SSL *ssl);
+
+=head1 DESCRIPTION
+
+These functions load the certificates and private keys into the SSL_CTX
+or SSL object, respectively.
+
+The SSL_CTX_* class of functions loads the certificates and keys into the
+SSL_CTX object B<ctx>. The information is passed to SSL objects B<ssl>
+created from B<ctx> with L<SSL_new(3)|SSL_new(3)> by copying, so that
+changes applied to B<ctx> do not propagate to already existing SSL objects.
+
+The SSL_* class of functions only loads certificates and keys into a
+specific SSL object. The specific information is kept, when
+L<SSL_clear(3)|SSL_clear(3)> is called for this SSL object.
+
+SSL_CTX_use_certificate() loads the certificate B<x> into B<ctx>,
+SSL_use_certificate() loads B<x> into B<ssl>. The rest of the
+certificates needed to form the complete certificate chain can be
+specified using the
+L<SSL_CTX_add_extra_chain_cert(3)|SSL_CTX_add_extra_chain_cert(3)>
+function.
+
+SSL_CTX_use_certificate_ASN1() loads the ASN1 encoded certificate from
+the memory location B<d> (with length B<len>) into B<ctx>,
+SSL_use_certificate_ASN1() loads the ASN1 encoded certificate into B<ssl>.
+
+SSL_CTX_use_certificate_file() loads the first certificate stored in B<file>
+into B<ctx>. The formatting B<type> of the certificate must be specified
+from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1.
+SSL_use_certificate_file() loads the certificate from B<file> into B<ssl>.
+See the NOTES section on why SSL_CTX_use_certificate_chain_file()
+should be preferred.
+
+SSL_CTX_use_certificate_chain_file() loads a certificate chain from
+B<file> into B<ctx>. The certificates must be in PEM format and must
+be sorted starting with the certificate to the highest level (root CA).
+There is no corresponding function working on a single SSL object.
+
+SSL_CTX_use_PrivateKey() adds B<pkey> as private key to B<ctx>.
+SSL_CTX_use_RSAPrivateKey() adds the private key B<rsa> of type RSA
+to B<ctx>. SSL_use_PrivateKey() adds B<pkey> as private key to B<ssl>;
+SSL_use_RSAPrivateKey() adds B<rsa> as private key of type RSA to B<ssl>.
+
+SSL_CTX_use_PrivateKey_ASN1() adds the private key of type B<pk>
+stored at memory location B<d> (length B<len>) to B<ctx>.
+SSL_CTX_use_RSAPrivateKey_ASN1() adds the private key of type RSA
+stored at memory location B<d> (length B<len>) to B<ctx>.
+SSL_use_PrivateKey_ASN1() and SSL_use_RSAPrivateKey_ASN1() add the private
+key to B<ssl>.
+
+SSL_CTX_use_PrivateKey_file() adds the first private key found in
+B<file> to B<ctx>. The formatting B<type> of the certificate must be specified
+from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1.
+SSL_CTX_use_RSAPrivateKey_file() adds the first private RSA key found in
+B<file> to B<ctx>. SSL_use_PrivateKey_file() adds the first private key found
+in B<file> to B<ssl>; SSL_use_RSAPrivateKey_file() adds the first private
+RSA key found to B<ssl>.
+
+SSL_CTX_check_private_key() checks the consistency of a private key with
+the corresponding certificate loaded into B<ctx>. If more than one
+key/certificate pair (RSA/DSA) is installed, the last item installed will
+be checked. If e.g. the last item was a RSA certificate or key, the RSA
+key/certificate pair will be checked. SSL_check_private_key() performs
+the same check for B<ssl>. If no key/certificate was explicitly added for
+this B<ssl>, the last item added into B<ctx> will be checked.
+
+=head1 NOTES
+
+The internal certificate store of OpenSSL can hold two private key/certificate
+pairs at a time: one key/certificate of type RSA and one key/certificate
+of type DSA. The certificate used depends on the cipher select, see
+also L<SSL_CTX_set_cipher_list(3)|SSL_CTX_set_cipher_list(3)>.
+
+When reading certificates and private keys from file, files of type
+SSL_FILETYPE_ASN1 (also known as B<DER>, binary encoding) can only contain
+one certificate or private key, consequently
+SSL_CTX_use_certificate_chain_file() is only applicable to PEM formatting.
+Files of type SSL_FILETYPE_PEM can contain more than one item.
+
+SSL_CTX_use_certificate_chain_file() adds the first certificate found
+in the file to the certificate store. The other certificates are added
+to the store of chain certificates using
+L<SSL_CTX_add_extra_chain_cert(3)|SSL_CTX_add_extra_chain_cert(3)>.
+There exists only one extra chain store, so that the same chain is appended
+to both types of certificates, RSA and DSA! If it is not intended to use
+both type of certificate at the same time, it is recommended to use the
+SSL_CTX_use_certificate_chain_file() instead of the
+SSL_CTX_use_certificate_file() function in order to allow the use of
+complete certificate chains even when no trusted CA storage is used or
+when the CA issuing the certificate shall not be added to the trusted
+CA storage.
+
+If additional certificates are needed to complete the chain during the
+TLS negotiation, CA certificates are additionally looked up in the
+locations of trusted CA certificates, see
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>.
+
+The private keys loaded from file can be encrypted. In order to successfully
+load encrypted keys, a function returning the passphrase must have been
+supplied, see
+L<SSL_CTX_set_default_passwd_cb(3)|SSL_CTX_set_default_passwd_cb(3)>.
+(Certificate files might be encrypted as well from the technical point
+of view, it however does not make sense as the data in the certificate
+is considered public anyway.)
+
+=head1 RETURN VALUES
+
+On success, the functions return 1.
+Otherwise check out the error stack to find out the reason.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_new(3)|SSL_new(3)>, L<SSL_clear(3)|SSL_clear(3)>,
+L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>,
+L<SSL_CTX_set_default_passwd_cb(3)|SSL_CTX_set_default_passwd_cb(3)>,
+L<SSL_CTX_set_cipher_list(3)|SSL_CTX_set_cipher_list(3)>,
+L<SSL_CTX_add_extra_chain_cert(3)|SSL_CTX_add_extra_chain_cert(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_get_client_CA_list.pod b/crypto/openssl/doc/ssl/SSL_get_client_CA_list.pod
new file mode 100644
index 000000000000..40e01cf9c81e
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_get_client_CA_list.pod
@@ -0,0 +1,52 @@
+=pod
+
+=head1 NAME
+
+SSL_get_client_CA_list, SSL_CTX_get_client_CA_list - get list of client CAs
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ STACK_OF(X509_NAME) *SSL_get_client_CA_list(SSL *s);
+ STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(SSL_CTX *ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_get_client_CA_list() returns the list of client CAs explicitly set for
+B<ctx> using L<SSL_CTX_set_client_CA_list(3)|SSL_CTX_set_client_CA_list(3)>.
+
+SSL_get_client_CA_list() returns the list of client CAs explicitly
+set for B<ssl> using SSL_set_client_CA_list() or B<ssl>'s SSL_CTX object with
+L<SSL_CTX_set_client_CA_list(3)|SSL_CTX_set_client_CA_list(3)>, when in
+server mode. In client mode, SSL_get_client_CA_list returns the list of
+client CAs sent from the server, if any.
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_client_CA_list() and SSL_set_client_CA_list() do not return
+diagnostic information.
+
+SSL_CTX_add_client_CA() and SSL_add_client_CA() have the following return
+values:
+
+=over 4
+
+=item STACK_OF(X509_NAMES)
+
+List of CA names explicitly set (for B<ctx> or in server mode) or send
+by the server (client mode).
+
+=item NULL
+
+No client CA list was explicitly set (for B<ctx> or in server mode) or
+the server did not send a list of CAs (client mode).
+
+=back
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>,
+L<SSL_CTX_set_client_CA_list(3)|SSL_CTX_set_client_CA_list(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_get_version.pod b/crypto/openssl/doc/ssl/SSL_get_version.pod
new file mode 100644
index 000000000000..24d52912565d
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_get_version.pod
@@ -0,0 +1,46 @@
+=pod
+
+=head1 NAME
+
+SSL_get_version - get the protocol version of a connection.
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ const char *SSL_get_version(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_get_cipher_version() returns the name of the protocol used for the
+connection B<ssl>.
+
+=head1 RETURN VALUES
+
+The following strings can occur:
+
+=over 4
+
+=item SSLv2
+
+The connection uses the SSLv2 protocol.
+
+=item SSLv3
+
+The connection uses the SSLv3 protocol.
+
+=item TLSv1
+
+The connection uses the TLSv1 protocol.
+
+=item unknown
+
+This indicates that no version has been set (no connection established).
+
+=back
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_set_connect_state.pod b/crypto/openssl/doc/ssl/SSL_set_connect_state.pod
new file mode 100644
index 000000000000..a8c4463c640a
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_set_connect_state.pod
@@ -0,0 +1,47 @@
+=pod
+
+=head1 NAME
+
+SSL_set_connect_state, SSL_get_accept_state - prepare SSL object to work in client or server mode
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ void SSL_set_connect_state(SSL *ssl);
+
+ void SSL_set_accept_state(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_set_connect_state() B<ssl> to work in client mode.
+
+SSL_set_accept_state() B<ssl> to work in server mode.
+
+=head1 NOTES
+
+When the SSL_CTX object was created with L<SSL_CTX_new(3)|SSL_CTX_new(3)>,
+it was either assigned a dedicated client method, a dedicated server
+method, or a generic method, that can be used for both client and
+server connections. (The method might have been changed with
+L<SSL_CTX_set_ssl_version(3)|SSL_CTX_set_ssl_version(3)> or
+SSL_set_ssl_method().)
+
+In order to successfully accomplish the handshake, the SSL routines need
+to know whether they should act in server or client mode. If the generic
+method was used, this is not clear from the method itself and must be set
+with either SSL_set_connect_state() or SSL_set_accept_state(). If these
+routines are not called, the default value set when L<SSL_new(3)|SSL_new(3)>
+is called is server mode.
+
+=head1 RETURN VALUES
+
+SSL_set_connect_state() and SSL_set_accept_state() do not return diagnostic
+information.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_new(3)|SSL_new(3)>, L<SSL_CTX_new(3)|SSL_CTX_new(3)>,
+L<SSL_CTX_set_ssl_version(3)|SSL_CTX_set_ssl_version(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/SSL_set_shutdown.pod b/crypto/openssl/doc/ssl/SSL_set_shutdown.pod
new file mode 100644
index 000000000000..6b196c1f15b8
--- /dev/null
+++ b/crypto/openssl/doc/ssl/SSL_set_shutdown.pod
@@ -0,0 +1,68 @@
+=pod
+
+=head1 NAME
+
+SSL_set_shutdown, SSL_get_shutdown - manipulate shutdown state of an SSL connection
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ void SSL_set_shutdown(SSL *ssl, int mode);
+
+ int SSL_get_shutdown(SSL *ssl);
+
+=head1 DESCRIPTION
+
+SSL_set_shutdown() sets the shutdown state of B<ssl> to B<mode>.
+
+SSL_get_shutdown() returns the shutdown mode of B<ssl>.
+
+=head1 NOTES
+
+The shutdown state of an ssl connection is a bitmask of:
+
+=over 4
+
+=item 0
+
+No shutdown setting, yet.
+
+=item SSL_SENT_SHUTDOWN
+
+A "close notify" shutdown alert was sent to the peer, the connection is being
+considered closed and the session is closed and correct.
+
+=item SSL_RECEIVED_SHUTDOWN
+
+A shutdown alert was received form the peer, either a normal "close notify"
+or a fatal error.
+
+=back
+
+SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the same time.
+
+The shutdown state of the connection is used to determine the state of
+the ssl session. If the session is still open, when
+L<SSL_clear(3)|SSL_clear(3)> or L<SSL_free(3)|SSL_free(3)> is called,
+it is considered bad and removed according to RFC2246.
+The actual condition for a correctly closed session is SSL_SENT_SHUTDOWN.
+SSL_set_shutdown() can be used to set this state without sending a
+close alert to the peer (see L<SSL_shutdown(3)|SSL_shutdown(3)>).
+
+If a "close notify" was received, SSL_RECEIVED_SHUTDOWN will be set,
+for setting SSL_SENT_SHUTDOWN the application must however still call
+L<SSL_shutdown(3)|SSL_shutdown(3)> or SSL_set_shutdown() itself.
+
+=head1 RETURN VALUES
+
+SSL_set_shutdown() does not return diagnostic information.
+
+SSL_get_shutdown() returns the current setting.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>, L<SSL_shutdown(3)|SSL_shutdown(3)>,
+L<SSL_clear(3)|SSL_clear(3)>, L<SSL_free(3)|SSL_free(3)>
+
+=cut
diff --git a/crypto/openssl/doc/ssl/d2i_SSL_SESSION.pod b/crypto/openssl/doc/ssl/d2i_SSL_SESSION.pod
new file mode 100644
index 000000000000..9a1ba6c47b21
--- /dev/null
+++ b/crypto/openssl/doc/ssl/d2i_SSL_SESSION.pod
@@ -0,0 +1,56 @@
+=pod
+
+=head1 NAME
+
+d2i_SSL_SESSION, i2d_SSL_SESSION - convert SSL_SESSION object from/to ASN1 representation
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, unsigned char **pp, long length);
+ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
+
+=head1 DESCRIPTION
+
+d2i_SSL_SESSION() transforms the external ASN1 representation of an SSL/TLS
+session, stored as binary data at location B<pp> with length B<length>, into
+an SSL_SESSION object.
+
+i2d_SSL_SESSION() transforms the SSL_SESSION object B<in> into the ASN1
+representation and stores it into the memory location pointed to by B<pp>.
+The length of the resulting ASN1 representation is returned. If B<pp> is
+the NULL pointer, only the length is calculated and returned.
+
+=head1 NOTES
+
+The SSL_SESSION object is built from several malloc()ed parts, it can
+therefore not be moved, copied or stored directly. In order to store
+session data on disk or into a database, it must be transformed into
+a binary ASN1 representation.
+
+When using d2i_SSL_SESSION(), the SSL_SESSION object is automatically
+allocated.
+
+When using i2d_SSL_SESSION(), the memory location pointed to by B<pp> must be
+large enough to hold the binary representation of the session. There is no
+known limit on the size of the created ASN1 representation, so the necessary
+amount of space should be obtained by first calling i2d_SSL_SESSION() with
+B<pp=NULL>, and obtain the size needed, then allocate the memory and
+call i2d_SSL_SESSION() again.
+
+=head1 RETURN VALUES
+
+d2i_SSL_SESSION() returns a pointer to the newly allocated SSL_SESSION
+object. In case of failure the NULL-pointer is returned and the error message
+can be retrieved from the error stack.
+
+i2d_SSL_SESSION() returns the size of the ASN1 representation in bytes.
+When the session is not valid, B<0> is returned and no operation is performed.
+
+=head1 SEE ALSO
+
+L<ssl(3)|ssl(3)>,
+L<SSL_CTX_sess_set_get_cb(3)|SSL_CTX_sess_set_get_cb(3)>
+
+=cut
diff --git a/crypto/openssl/test/bctest b/crypto/openssl/test/bctest
new file mode 100755
index 000000000000..17b75d4ecabd
--- /dev/null
+++ b/crypto/openssl/test/bctest
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+# This script is used by test/Makefile.ssl to check whether a sane 'bc'
+# is installed.
+# ('make test_bn' should not try to run 'bc' if it does not exist or if
+# it is a broken 'bc' version that is known to cause trouble.)
+#
+# If 'bc' works, we also test if it knows the 'print' command.
+#
+# In any case, output an appropriate command line for running (or not
+# running) bc.
+
+
+IFS=:
+for dir in $PATH; do
+ bc="$dir/bc"
+
+ if [ -x "$bc" -a ! -d "$bc" ]; then
+ failure=none
+
+
+ # Test for SunOS 5.[78] bc bug
+ "$bc" >tmp.bctest <<\EOF
+obase=16
+ibase=16
+a=AD88C418F31B3FC712D0425001D522B3AE9134FF3A98C13C1FCC1682211195406C1A6C66C6A\
+CEEC1A0EC16950233F77F1C2F2363D56DD71A36C57E0B2511FC4BA8F22D261FE2E9356D99AF57\
+10F3817C0E05BF79C423C3F66FDF321BE8D3F18F625D91B670931C1EF25F28E489BDA1C5422D1\
+C3F6F7A1AD21585746ECC4F10A14A778AF56F08898E965E9909E965E0CB6F85B514150C644759\
+3BE731877B16EA07B552088FF2EA728AC5E0FF3A23EB939304519AB8B60F2C33D6BA0945B66F0\
+4FC3CADF855448B24A9D7640BCF473E
+b=DCE91E7D120B983EA9A104B5A96D634DD644C37657B1C7860B45E6838999B3DCE5A555583C6\
+9209E41F413422954175A06E67FFEF6746DD652F0F48AEFECC3D8CAC13523BDAAD3F5AF4212BD\
+8B3CD64126E1A82E190228020C05B91C8B141F1110086FC2A4C6ED631EBA129D04BB9A19FC53D\
+3ED0E2017D60A68775B75481449
+(a/b)*b + (a%b) - a
+EOF
+ if [ 0 != "`cat tmp.bctest`" ]; then
+ failure=SunOStest
+ fi
+
+
+ if [ "$failure" = none ]; then
+ # Test for SCO bc bug.
+ "$bc" >tmp.bctest <<\EOF
+obase=16
+ibase=16
+-FFDD63BA1A4648F0D804F8A1C66C53F0D2110590E8A3907EC73B4AEC6F15AC177F176F2274D2\
+9DC8022EA0D7DD3ABE9746D2D46DD3EA5B5F6F69DF12877E0AC5E7F5ADFACEE54573F5D256A06\
+11B5D2BC24947724E22AE4EC3FB0C39D9B4694A01AFE5E43B4D99FB9812A0E4A5773D8B254117\
+1239157EC6E3D8D50199 * -FFDD63BA1A4648F0D804F8A1C66C53F0D2110590E8A3907EC73B4\
+AEC6F15AC177F176F2274D29DC8022EA0D7DD3ABE9746D2D46DD3EA5B5F6F69DF12877E0AC5E7\
+F5ADFACEE54573F5D256A0611B5D2BC24947724E22AE4EC3FB0C39D9B4694A01AFE5E43B4D99F\
+B9812A0E4A5773D8B2541171239157EC6E3D8D50199 - FFBACC221682DA464B6D7F123482522\
+02EDAEDCA38C3B69E9B7BBCD6165A9CD8716C4903417F23C09A85B851961F92C217258CEEB866\
+85EFCC5DD131853A02C07A873B8E2AF2E40C6D5ED598CD0E8F35AD49F3C3A17FDB7653E4E2DC4\
+A8D23CC34686EE4AD01F7407A7CD74429AC6D36DBF0CB6A3E302D0E5BDFCD048A3B90C1BE5AA8\
+E16C3D5884F9136B43FF7BB443764153D4AEC176C681B078F4CC53D6EB6AB76285537DDEE7C18\
+8C72441B52EDBDDBC77E02D34E513F2AABF92F44109CAFE8242BD0ECBAC5604A94B02EA44D43C\
+04E9476E6FBC48043916BFA1485C6093603600273C9C33F13114D78064AE42F3DC466C7DA543D\
+89C8D71
+AD534AFBED2FA39EE9F40E20FCF9E2C861024DB98DDCBA1CD118C49CA55EEBC20D6BA51B2271C\
+928B693D6A73F67FEB1B4571448588B46194617D25D910C6A9A130CC963155CF34079CB218A44\
+8A1F57E276D92A33386DDCA3D241DB78C8974ABD71DD05B0FA555709C9910D745185E6FE108E3\
+37F1907D0C56F8BFBF52B9704 % -E557905B56B13441574CAFCE2BD257A750B1A8B2C88D0E36\
+E18EF7C38DAC80D3948E17ED63AFF3B3467866E3B89D09A81B3D16B52F6A3C7134D3C6F5123E9\
+F617E3145BBFBE9AFD0D6E437EA4FF6F04BC67C4F1458B4F0F47B64 - 1C2BBBB19B74E86FD32\
+9E8DB6A8C3B1B9986D57ED5419C2E855F7D5469E35E76334BB42F4C43E3F3A31B9697C171DAC4\
+D97935A7E1A14AD209D6CF811F55C6DB83AA9E6DFECFCD6669DED7171EE22A40C6181615CAF3F\
+5296964
+EOF
+ if [ "0
+0" != "`cat tmp.bctest`" ]; then
+ failure=SCOtest
+ fi
+ fi
+
+
+ if [ "$failure" = none ]; then
+ # bc works; now check if it knows the 'print' command.
+ if [ "OK" = "`echo 'print \"OK\"' | $bc 2>/dev/null`" ]
+ then
+ echo "$bc"
+ else
+ echo "sed 's/print.*//' | $bc"
+ fi
+ exit 0
+ fi
+
+ echo "$bc does not work properly ('$failure' failed). Looking for another bc ..." >&2
+ fi
+done
+
+echo "No working bc found. Consider installing GNU bc." >&2
+echo "cat >/dev/null"
+exit 1
diff --git a/lib/libc/gen/getprogname.3 b/lib/libc/gen/getprogname.3
new file mode 100644
index 000000000000..74225956f5d7
--- /dev/null
+++ b/lib/libc/gen/getprogname.3
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 2001 Christopher G. Demetriou
+.\" 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 for the
+.\" NetBSD Project. See http://www.netbsd.org/ for
+.\" information about NetBSD.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2001
+.Dt GETPROGNAME 3
+.Os
+.Sh NAME
+.Nm getprogname ,
+.Nm setprogname
+.Nd get or set the program name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Ft const char *
+.Fn getprogname "void"
+.Ft void
+.Fn setprogname "const char *progname"
+.Sh DESCRIPTION
+The
+.Fn getprogname
+and
+.Fn setprogname
+functions manipulate the name of the current program.
+They are used by error-reporting routines to produce
+consistent output.
+.Pp
+The
+.Fn getprogname
+function returns the name of the program.
+If the name has not been set yet, it will return
+.Dv NULL .
+.Pp
+The
+.Fn setprogname
+function sets the name of the program.
+Since a pointer to the given string is kept as the program name,
+it should not be modified for the rest of the program's lifetime.
+.Pp
+In
+.Fx ,
+the name of the program is set by the start-up code that is run before
+.Fn main ;
+thus,
+running
+.Fn setprogname
+is not necessary.
+Programs that desire maximum portability should still call it;
+on another operating system,
+these functions may be implemented in a portability library.
+Calling
+.Fn setprogname
+allows the aforementioned library to learn the program name without
+modifications to the start-up code.
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr setproctitle 3
+.Sh HISTORY
+These functions first appeared in
+.Nx 1.6 ,
+and made their way into
+.Fx 5.0 .
diff --git a/lib/libc/gen/getprogname.c b/lib/libc/gen/getprogname.c
new file mode 100644
index 000000000000..54f721ab665c
--- /dev/null
+++ b/lib/libc/gen/getprogname.c
@@ -0,0 +1,13 @@
+#if defined(LIBC_RCS) && !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* LIBC_RCS and not lint */
+
+extern const char *__progname;
+
+const char *
+getprogname(void)
+{
+
+ return (__progname);
+}
diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c
new file mode 100644
index 000000000000..6c56013ef7c4
--- /dev/null
+++ b/lib/libc/gen/setprogname.c
@@ -0,0 +1,13 @@
+#if defined(LIBC_RCS) && !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* LIBC_RCS and not lint */
+
+extern const char *__progname;
+
+void
+setprogname(const char *progname)
+{
+
+ __progname = progname;
+}
diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c
new file mode 100644
index 000000000000..ecc24310ae4b
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.c
@@ -0,0 +1,184 @@
+/* $NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2001 Christopher G. Demetriou
+ * 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 for the
+ * NetBSD Project. See http://www.netbsd.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+ */
+
+/*
+ * hcreate() / hsearch() / hdestroy()
+ *
+ * SysV/XPG4 hash table functions.
+ *
+ * Implementation done based on NetBSD manual page and Solaris manual page,
+ * plus my own personal experience about how they're supposed to work.
+ *
+ * I tried to look at Knuth (as cited by the Solaris manual page), but
+ * nobody had a copy in the office, so...
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include "namespace.h"
+
+/*
+ * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
+ * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
+ */
+struct internal_entry {
+ SLIST_ENTRY(internal_entry) link;
+ ENTRY ent;
+};
+SLIST_HEAD(internal_head, internal_entry);
+
+#define MIN_BUCKETS_LG2 4
+#define MIN_BUCKETS (1 << MIN_BUCKETS_LG2)
+
+/*
+ * max * sizeof internal_entry must fit into size_t.
+ * assumes internal_entry is <= 32 (2^5) bytes.
+ */
+#define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
+#define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2)
+
+/* Default hash function, from db/hash/hash_func.c */
+extern u_int32_t (*__default_hash)(const void *, size_t);
+
+static struct internal_head *htable;
+static size_t htablesize;
+
+int
+hcreate(size_t nel)
+{
+ size_t idx;
+ unsigned int p2;
+
+ /* Make sure this this isn't called when a table already exists. */
+ if (htable != NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* If nel is too small, make it min sized. */
+ if (nel < MIN_BUCKETS)
+ nel = MIN_BUCKETS;
+
+ /* If it's too large, cap it. */
+ if (nel > MAX_BUCKETS)
+ nel = MAX_BUCKETS;
+
+ /* If it's is not a power of two in size, round up. */
+ if ((nel & (nel - 1)) != 0) {
+ for (p2 = 0; nel != 0; p2++)
+ nel >>= 1;
+ nel = 1 << p2;
+ }
+
+ /* Allocate the table. */
+ htablesize = nel;
+ htable = malloc(htablesize * sizeof htable[0]);
+ if (htable == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ /* Initialize it. */
+ for (idx = 0; idx < htablesize; idx++)
+ SLIST_INIT(&htable[idx]);
+
+ return 1;
+}
+
+void
+hdestroy(void)
+{
+ struct internal_entry *ie;
+ size_t idx;
+
+ if (htable == NULL)
+ return;
+
+ for (idx = 0; idx < htablesize; idx++) {
+ while (!SLIST_EMPTY(&htable[idx])) {
+ ie = SLIST_FIRST(&htable[idx]);
+ SLIST_REMOVE_HEAD(&htable[idx], link);
+ free(ie->ent.key);
+ free(ie);
+ }
+ }
+ free(htable);
+ htable = NULL;
+}
+
+ENTRY *
+hsearch(ENTRY item, ACTION action)
+{
+ struct internal_head *head;
+ struct internal_entry *ie;
+ uint32_t hashval;
+ size_t len;
+
+ len = strlen(item.key);
+ hashval = (*__default_hash)(item.key, len);
+
+ head = &htable[hashval & (htablesize - 1)];
+ ie = SLIST_FIRST(head);
+ while (ie != NULL) {
+ if (strcmp(ie->ent.key, item.key) == 0)
+ break;
+ ie = SLIST_NEXT(ie, link);
+ }
+
+ if (ie != NULL)
+ return &ie->ent;
+ else if (action == FIND)
+ return NULL;
+
+ ie = malloc(sizeof *ie);
+ if (ie == NULL)
+ return NULL;
+ ie->ent.key = item.key;
+ ie->ent.data = item.data;
+
+ SLIST_INSERT_HEAD(head, ie, link);
+ return &ie->ent;
+}
diff --git a/lib/libc/string/wmemchr.3 b/lib/libc/string/wmemchr.3
new file mode 100644
index 000000000000..ff82e73a3564
--- /dev/null
+++ b/lib/libc/string/wmemchr.3
@@ -0,0 +1,145 @@
+.\" $NetBSD: wmemchr.3,v 1.4 2001/01/02 11:26:23 itojun Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 22, 2000
+.Dt WMEMCHR 3
+.Os
+.Sh NAME
+.Nm wmemchr ,
+.Nm wmemcmp ,
+.Nm wmemcpy ,
+.Nm wmemmove ,
+.Nm wmemset ,
+.Nm wcscat ,
+.Nm wcschr ,
+.Nm wcscmp ,
+.Nm wcscpy ,
+.Nm wcscspn ,
+.Nm wcslcat ,
+.Nm wcslcpy ,
+.Nm wcslen ,
+.Nm wcsncat ,
+.Nm wcsncmp ,
+.Nm wcsncpy ,
+.Nm wcspbrk ,
+.Nm wcsrchr ,
+.Nm wcsspn ,
+.Nm wcsstr
+.Nd wide character string manipulation operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <wchar.h>
+.Ft wchar_t *
+.Fn wmemchr "const wchar_t *s" "wchar_t c" "size_t n"
+.Ft int
+.Fn wmemcmp "const wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemcpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemmove "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemset "wchar_t *s" "wchar_t c" "size_t n"
+.Ft wchar_t *
+.Fn wcscat "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft wchar_t *
+.Fn wcschr "const wchar_t *s" "wchar_t c"
+.Ft int
+.Fn wcscmp "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcscpy "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft size_t
+.Fn wcscspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft size_t
+.Fn wcslcat "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslcpy "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslen "const wchar_t *s"
+.Ft wchar_t *
+.Fn wcsncat "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft int
+.Fn wcsncmp "const wchar_t *s1" "const wchar_t * s2" "size_t n"
+.Ft wchar_t *
+.Fn wcsncpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft wchar_t *
+.Fn wcspbrk "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsrchr "const wchar_t *s" "wchar_t c"
+.Ft size_t
+.Fn wcsspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsstr "const wchar_t *s1" "const wchar_t *s2"
+.Sh DESCRIPTION
+The functions implement string manipulation operations over wide character
+strings.
+For a detailed description, refer to documents for the respective single-byte
+counterpart, such as
+.Xr memchr 3 .
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr memcmp 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr memset 3 ,
+.Xr strcat 3 ,
+.Xr strchr 3 ,
+.Xr strcmp 3 ,
+.Xr strcpy 3 ,
+.Xr strcspn 3 ,
+.Xr strlcat 3 ,
+.Xr strlcpy 3 ,
+.Xr strlen 3 ,
+.Xr strncat 3 ,
+.Xr strncmp 3 ,
+.Xr strncpy 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3
+.Sh STANDARDS
+These functions conform to
+.St -isoC-99 ,
+with the exception of
+.Fn wcslcat
+and
+.Fn wcslcpy ,
+which are extensions.
diff --git a/lib/libc_r/test/join_leak_d.c b/lib/libc_r/test/join_leak_d.c
new file mode 100644
index 000000000000..6532ca5bfc74
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone@freebsd.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(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(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.
+ *
+ * $FreeBSD$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libc_r/test/join_leak_d.exp b/lib/libc_r/test/join_leak_d.exp
new file mode 100644
index 000000000000..369a88dd2404
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libpam/modules/pam_krb5/COPYRIGHT b/lib/libpam/modules/pam_krb5/COPYRIGHT
new file mode 100644
index 000000000000..42fb642c7230
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/COPYRIGHT
@@ -0,0 +1,195 @@
+pam_krb5:
+
+$FreeBSD$
+
+Copyright (c) Frank Cusack, 1999-2000.
+fcusack@fcusack.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.
+
+---------------------------------------------------------------------------
+
+This software may contain code from Naomaru Itoi:
+
+PAM-kerberos5 module Copyright notice.
+Naomaru Itoi <itoi@eecs.umich.edu>, June 24, 1997.
+
+----------------------------------------------------------------------------
+COPYRIGHT (c) 1997
+THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ALL RIGHTS RESERVED
+
+PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE
+THIS SOFTWARE AND SUCH DERIVATIVE WORKS FOR ANY PURPOSE, SO LONG AS THE NAME
+OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC,
+WRITTEN PRIOR AUTHORIZATION. IF THE ABOVE COPYRIGHT NOTICE OR ANY OTHER
+IDENTIFICATION OF THE UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST ALSO BE INCLUDED.
+
+THE SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY OF
+MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE
+UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABITILY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN
+CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+PAM-kerberos5 module is written based on PAM-kerberos4 module
+by Derrick J. Brashear and kerberos5-1.0pl1 by M.I.T. kerberos team.
+Permission to use, copy, modify, distribute this software is hereby
+granted, as long as it is granted by Derrick J. Brashear and
+M.I.T. kerberos team. Followings are their copyright information.
+----------------------------------------------------------------------------
+
+This software may contain code from Derrick J. Brashear:
+
+
+Copyright (c) Derrick J. Brashear, 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.
+
+----------------------------------------------------------------------------
+
+This software may contain code from MIT Kerberos 5:
+
+Copyright Notice and Legal Administrivia
+----------------------------------------
+
+Copyright (C) 1996 by the Massachusetts Institute of Technology.
+
+All rights reserved.
+
+Export of this software from the United States of America may require
+a specific license from the United States Government. It is the
+responsibility of any person or organization contemplating export to
+obtain such a license before exporting.
+
+WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+distribute this software and its documentation for any purpose and
+without fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation, and that
+the name of M.I.T. not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission. M.I.T. makes no representations about the suitability of
+this software for any purpose. It is provided "as is" without express
+or implied warranty.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+Individual source code files are copyright MIT, Cygnus Support,
+OpenVision, Oracle, Sun Soft, and others.
+
+Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+and Zephyr are trademarks of the Massachusetts Institute of Technology
+(MIT). No commercial use of these trademarks may be made without
+prior written permission of MIT.
+
+"Commercial use" means use of a name in a product or other for-profit
+manner. It does NOT prevent a commercial firm from referring to the
+MIT trademarks in order to convey information (although in doing so,
+recognition of their trademark status should be given).
+
+The following copyright and permission notice applies to the
+OpenVision Kerberos Administration system located in kadmin/create,
+kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions
+of lib/rpc:
+
+ Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved
+
+ WARNING: Retrieving the OpenVision Kerberos Administration system
+ source code, as described below, indicates your acceptance of the
+ following terms. If you do not agree to the following terms, do not
+ retrieve the OpenVision Kerberos administration system.
+
+ You may freely use and distribute the Source Code and Object Code
+ compiled from it, with or without modification, but this Source
+ Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY,
+ INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR
+ FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER
+ EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY
+ FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING,
+ WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE
+ CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY
+ OTHER REASON.
+
+ OpenVision retains all copyrights in the donated Source Code. OpenVision
+ also retains copyright to derivative works of the Source Code, whether
+ created by OpenVision or by a third party. The OpenVision copyright
+ notice must be preserved if derivative works are made based on the
+ donated Source Code.
+
+ OpenVision Technologies, Inc. has donated this Kerberos
+ Administration system to MIT for inclusion in the standard
+ Kerberos 5 distribution. This donation underscores our
+ commitment to continuing Kerberos technology development
+ and our gratitude for the valuable work which has been
+ performed by MIT and the Kerberos community.
+
+
diff --git a/lib/libpam/modules/pam_krb5/README b/lib/libpam/modules/pam_krb5/README
new file mode 100644
index 000000000000..ee97421bfa9d
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/README
@@ -0,0 +1,72 @@
+$FreeBSD$
+
+This is the README for pam_krb5, a PAM module which support Kerberos 5
+authentication.
+
+This software is Copyright (c) 1999-2000 Frank Cusack.
+All Rights Reserved.
+
+See the COPYRIGHT file, included with this distribution, for copyright
+and redistribution information.
+
+Author:
+Frank Cusack
+<fcusack@fcusack.com>
+
+
+I. Kerberos notes
+
+This PAM module requires the MIT 1.1+ release of Kerberos, or the Cygnus
+CNS distribution. It has not been tested against heimdal or any other
+Kerberos distributions.
+
+Unlike other PAM Kerberos 5 modules out there, this one does not
+use any private Kerberos interfaces. Thus, you need only the
+header files and libraries that are part of the Kerberos distribution.
+
+
+II. OS notes
+
+This software has been tested against Solaris 2.6. It should compile
+against Linux (distributions?) with minimal (if any) changes. Reports
+of OS [in]compatibilities are welcomed.
+
+dtlogin on Solaris doesn't support xrealm logins (probably a good thing).
+
+III. PAM notes/open issues
+
+auth module:
+When is pam_sm_setcred() ever called with flags other than PAM_ESTABLISH_CRED
+or PAM_DELETE_CRED?
+
+acct module:
+I believe this to be complete.
+
+session module:
+This is complete (both functions just return success).
+
+passwd module:
+When is pam_sm_chauthtok() ever called with flags other than
+PAM_UPDATE_AUTHTOK?
+
+
+IV. Usage
+
+Simply change /etc/pam.conf to include this module. Make sure to include
+the acct category whenever you use the auth category, or .k5login will
+not get checked.
+
+You probably want to make this module "sufficient", before your unix
+(or other) module(s).
+
+
+V. Acknowledgements
+
+Thanks to Naomaru Itoi <itoi@eecs.umich.edu>,
+Curtis King <curtis.king@cul.ca>, and Derrick Brashear <shadow@dementia.org>,
+all of whom have written and made available Kerberos 4/5 modules.
+Although no code in this module is directly from these author's modules,
+(except the get_user_info() routine in support.c; derived from whichever
+of these authors originally wrote the first module the other 2 copied from),
+it was extremely helpful to look over their code which aided in my design.
+
diff --git a/lib/libpam/modules/pam_krb5/TODO b/lib/libpam/modules/pam_krb5/TODO
new file mode 100644
index 000000000000..1f0939f256c8
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/TODO
@@ -0,0 +1,16 @@
+$FreeBSD$
+
+Things for 1.1, in no particular order:
+
+Check against Solaris 7, Solaris 8 beta. Check SEAM compatibility.
+Check against Linux (Redhat, others?).
+Check against HPUX.
+Fix PAM flags checking.
+Add more debugging for successful calls.
+Move "entry" debugging up.
+Check bounds on str* calls. [paranoia]
+
+Get defaults from krb5.conf?
+** Allow no-xrealm, this module typically used for local login **
+** Add notes about runtime text relocation on Solaris **
+
diff --git a/lib/libpam/modules/pam_krb5/compat_heimdal.c b/lib/libpam/modules/pam_krb5/compat_heimdal.c
new file mode 100644
index 000000000000..fb4e1025e6ef
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/compat_heimdal.c
@@ -0,0 +1,141 @@
+/*
+ * compat_heimdal.c
+ *
+ * Heimdal compatability layer.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <krb5.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include "pam_krb5.h"
+
+const char *
+compat_princ_component(krb5_context context, krb5_principal princ, int n)
+{
+ return princ->name.name_string.val[n];
+}
+
+void
+compat_free_data_contents(krb5_context context, krb5_data *data)
+{
+ krb5_xfree(data->data);
+}
+
+krb5_error_code
+compat_cc_next_cred(krb5_context context, const krb5_ccache id,
+ krb5_cc_cursor *cursor, krb5_creds *creds)
+{
+ return krb5_cc_next_cred(context, id, creds, cursor);
+}
+
+
+static krb5_error_code
+heimdal_pam_prompter(krb5_context context, void *data, const char *banner, int
+ num_prompts, krb5_prompt prompts[])
+{
+ int pam_prompts = num_prompts;
+ int pamret, i;
+
+ struct pam_message *msg;
+ struct pam_response *resp = NULL;
+ struct pam_conv *conv;
+ pam_handle_t *pamh = (pam_handle_t *) data;
+
+ if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
+ return KRB5KRB_ERR_GENERIC;
+
+ if (banner)
+ pam_prompts++;
+
+ msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
+ if (!msg)
+ return ENOMEM;
+
+ /* Now use pam_prompts as an index */
+ pam_prompts = 0;
+
+ if (banner) {
+ msg[pam_prompts].msg = malloc(strlen(banner) + 1);
+ if (!msg[pam_prompts].msg)
+ goto cleanup;
+ strcpy((char *) msg[pam_prompts].msg, banner);
+ msg[pam_prompts].msg_style = PAM_TEXT_INFO;
+ pam_prompts++;
+ }
+
+ for (i = 0; i < num_prompts; i++) {
+ msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
+ if (!msg[pam_prompts].msg)
+ goto cleanup;
+ sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
+ msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
+ : PAM_PROMPT_ECHO_ON;
+ pam_prompts++;
+ }
+
+ if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg,
+ &resp, conv->appdata_ptr)) != 0)
+ goto cleanup;
+
+ if (!resp)
+ goto cleanup;
+
+ /* Reuse pam_prompts as a starting index */
+ pam_prompts = 0;
+ if (banner)
+ pam_prompts++;
+
+ for (i = 0; i < num_prompts; i++, pam_prompts++) {
+ register int len;
+ if (!resp[pam_prompts].resp) {
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
+ if (len > prompts[i].reply->length) {
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
+ prompts[i].reply->length = len;
+ }
+
+cleanup:
+ /* pam_prompts is correct at this point */
+
+ for (i = 0; i < pam_prompts; i++) {
+ if (msg[i].msg)
+ free((char *) msg[i].msg);
+ }
+ free(msg);
+
+ if (resp) {
+ for (i = 0; i < pam_prompts; i++) {
+ /*
+ * Note that PAM is underspecified wrt free()'ing resp[i].resp.
+ * It's not clear if I should free it, or if the application
+ * has to. Therefore most (all?) apps won't free() it, and I
+ * can't either, as I am not sure it was malloc()'d. All PAM
+ * implementations I've seen leak memory here. Not so bad, IFF
+ * you fork/exec for each PAM authentication (as is typical).
+ */
+#if 0
+ if (resp[i].resp)
+ free(resp[i].resp);
+#endif /* 0 */
+ }
+ /* This does not lose resp[i].resp if the application saved a copy. */
+ free(resp);
+ }
+
+ return (pamret ? KRB5KRB_ERR_GENERIC : 0);
+}
+
+krb5_prompter_fct pam_prompter = heimdal_pam_prompter;
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.8 b/lib/libpam/modules/pam_krb5/pam_krb5.8
new file mode 100644
index 000000000000..7ef121170fb2
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.8
@@ -0,0 +1,191 @@
+.\"
+.\" $Id: pam_krb5.5,v 1.5 2000/01/05 00:59:56 fcusack Exp $
+.\" $FreeBSD$
+.TH pam_krb5 8 "15 Jan 1999"
+.SH NAME
+pam_krb5 \- Kerberos 5 PAM module
+.SH SYNOPSIS
+.LP
+.B /usr/lib/pam_krb5.so
+.LP
+.SH DESCRIPTION
+.IX "pam_krb5" "" "\fLpam_krb5\fP \(em Kerberos 5 PAM module"
+.PP
+The Kerberos 5 service module for PAM, typically
+.BR /usr/lib/pam_krb5.so ,
+provides functionality for three PAM categories:
+authentication,
+account management,
+and password management.
+It also provides null functions for session management.
+The
+.B pam_krb5.so
+module is a shared object
+that can be dynamically loaded to provide
+the necessary functionality upon demand.
+Its path is specified in the
+.SM PAM
+configuration file.
+.SH Kerberos 5 Authentication Module
+The Kerberos 5 authentication component
+provides functions to verify the identity of a user.
+(\f3pam_sm_authenticate(\|)\f1)
+and to set user specific credentials
+(\f3pam_sm_setcred(\|)\f1).
+.B pam_sm_authenticate(\|)
+converts the supplied username into a Kerberos principal,
+by appending the default local realm name.
+It also supports usernames with explicit realm names.
+If a realm name is supplied, then upon a sucessful return, it
+changes the username by mapping the principal name into a local username
+(calling \f3krb5_aname_to_localname()\f1). This typically just means
+the realm name is stripped.
+.LP
+It prompts the user for a password and obtains a new Kerberos TGT for
+the principal. The TGT is verified by obtaining a service
+ticket for the local host.
+.LP
+When prompting for the current password, the authentication
+module will use the prompt "Password for <principal>: ".
+.LP
+The
+.B pam_sm_setcred(\|)
+function stores the newly acquired credentials in a credentials cache,
+and sets the environment variable
+.B KRB5CCNAME
+appropriately.
+The credentials cache should be destroyed by the user at logout with
+.BR kdestroy (1) .
+.LP
+The following options may be passed to the authentication module:
+.TP 15
+.B debug
+.BR syslog (3)
+debugging information at
+.SB LOG_DEBUG
+level.
+.TP
+.B use_first_pass
+If the authentication module is not the first in the stack,
+and a previous module obtained the user's password, that password is
+used to authenticate the user. If this fails, the authentication
+module returns failure without prompting the user for a password.
+This option has no effect if the authentication module is
+the first in the stack, or if no previous modules obtained the
+user's password.
+.TP
+.B try_first_pass
+This option is similar to the
+.B use_first_pass
+option, except that if the previously obtained password fails, the
+user is prompted for another password.
+.TP
+.B forwardable
+Obtain forwardable Kerberos credentials for the user.
+.TP
+.B no_ccache
+Do not save the obtained credentials in a credentials cache. This is a
+useful option if the authentication module is used for services such
+as ftp or pop, where the user would not be able to destroy them. [This
+is not a recommendation to use the module for those services.]
+.TP
+.B ccache=<name>
+Use <name> as the credentials cache. <name> must be in the form
+.IR type:residual .
+The special tokens
+.BR %u ,
+to designate the decimal uid of the user;
+and
+.BR %p ,
+to designate the current process id; can be used in <name>.
+.SH Kerberos 5 Account Management Module
+The Kerberos 5 account management component
+provides a function to perform account management,
+.BR pam_sm_acct_mgmt(\|) .
+The function verifies that the authenticated principal is allowed
+to login to the local user account by calling
+.B krb5_kuserok()
+(which checks the user's \&.k5login file).
+.SH Kerberos 5 Password Management Module
+The Kerberos 5 password management component
+provides a function to change passwords
+(\f3pam_sm_chauthtok(\|)\f1). The username supplied (the
+user running the
+.BR passwd (1)
+command, or the username given as an argument) is mapped into
+a Kerberos principal name, using the same technique as in
+the authentication module. Note that if a realm name was
+explicitly supplied during authentication, but not during
+a password change, the mapping
+done by the password management module may not result in the
+same principal as was used for authentication.
+.LP
+Unlike when
+changing a unix password, the password management module will
+allow any user to change any principal's password (if the user knows
+the principal's old password, of course). Also unlike unix, root
+is always prompted for the principal's old password.
+.LP
+The password management module uses the same heuristics as
+.BR kpasswd (1)
+to determine how to contact the Kerberos password server.
+.LP
+The following options may be passed to the password management
+module:
+.TP 15
+.B debug
+.BR syslog (3)
+debugging information at
+.SB LOG_DEBUG
+level.
+.TP
+.B use_first_pass
+If the password management module is not the first in the stack,
+and a previous module obtained the user's old password, that password is
+used to authenticate the user. If this fails, the password
+management
+module returns failure without prompting the user for the old password.
+If successful, the new password entered to the previous module is also
+used as the new Kerberos password. If the new password fails,
+the password management module returns failure without
+prompting the user for a new password.
+.TP
+.B try_first_pass
+This option is similar to the
+.B use_first_pass
+option, except that if the previously obtained old or new passwords fail,
+the user is prompted for them.
+.SH Kerberos 5 Session Management Module
+The Kerberos 5 session management component
+provides functions to initiate
+(\f3pam_sm_open_session(\|)\f1)
+and terminate
+(\f3pam_sm_close_session(\|)\f1)
+sessions. Since session management is not defined under Kerberos 5,
+both of these functions simply return success. They are provided
+only because of the naming conventions for PAM modules.
+.SH ENVIRONMENT
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the credentials cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default credentials cache ([uid] is the decimal UID of the user).
+.TP
+~/\&.k5login
+file containing Kerberos principals that are allowed access.
+.SH SEE ALSO
+.BR kdestroy (1),
+.BR passwd (1),
+.BR pam (8),
+.BR syslog (3),
+.BR pam.conf (5).
+.SH NOTES
+Applications should not call
+.B pam_authenticate()
+more than once between calls to
+.B pam_start()
+and
+.B pam_end()
+when using the Kerberos 5 PAM module.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.h b/lib/libpam/modules/pam_krb5/pam_krb5.h
new file mode 100644
index 000000000000..ff0237321bdd
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.h
@@ -0,0 +1,23 @@
+/*
+ * pam_krb5.h
+ *
+ * $Id: pam_krb5.h,v 1.5 1999/01/19 23:43:10 fcusack Exp $
+ * $FreeBSD$
+ */
+
+int get_user_info(pam_handle_t *, char *, int, char **);
+int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int);
+void cleanup_cache(pam_handle_t *, void *, int);
+
+krb5_prompter_fct pam_prompter;
+
+const char *compat_princ_component(krb5_context, krb5_principal, int);
+void compat_free_data_contents(krb5_context, krb5_data *);
+krb5_error_code compat_cc_next_cred(krb5_context, const krb5_ccache,
+ krb5_cc_cursor *, krb5_creds *);
+
+#ifndef ENCTYPE_DES_CBC_MD5
+#define ENCTYPE_DES_CBC_MD5 ETYPE_DES_CBC_MD5
+#endif
+
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_acct.c b/lib/libpam/modules/pam_krb5/pam_krb5_acct.c
new file mode 100644
index 000000000000..1a2910bc1d8e
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_acct.c
@@ -0,0 +1,83 @@
+/*
+ * pam_krb5_acct.c
+ *
+ * PAM account management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_acct.c,v 1.3 1999/01/19 21:26:44 fcusack Exp $";
+
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_acct_mgmt(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Check authorization of user */
+int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_ccache ccache;
+ krb5_principal princ;
+
+ char *service, *name;
+ int debug = 0;
+ int i, pamret;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ }
+
+ /* Get username */
+ if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
+ return PAM_PERM_DENIED;;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if (pam_get_data(pamh, "ccache", (const void **) &ccache)) {
+ /* User did not use krb5 to login */
+ DLOG("ccache", "not found");
+ return PAM_SUCCESS;
+ }
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_PERM_DENIED;;
+ }
+
+ if ((krbret = krb5_cc_get_principal(pam_context, ccache, &princ)) != 0) {
+ DLOG("krb5_cc_get_principal()", error_message(krbret));
+ pamret = PAM_PERM_DENIED;;
+ goto cleanup;
+ }
+
+ if (krb5_kuserok(pam_context, princ, name))
+ pamret = PAM_SUCCESS;
+ else
+ pamret = PAM_PERM_DENIED;
+ krb5_free_principal(pam_context, princ);
+
+cleanup:
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_auth.c b/lib/libpam/modules/pam_krb5/pam_krb5_auth.c
new file mode 100644
index 000000000000..fd4270b7b3b2
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_auth.c
@@ -0,0 +1,505 @@
+/*
+ * pam_krb5_auth.c
+ *
+ * PAM authentication management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_auth.c,v 1.18 2000/01/04 08:44:08 fcusack Exp $";
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h> /* PATH_MAX */
+#include <pwd.h> /* getpwnam */
+#include <stdio.h> /* tmpnam */
+#include <stdlib.h> /* malloc */
+#include <strings.h> /* strchr */
+#include <syslog.h> /* syslog */
+#include <unistd.h> /* chown */
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+extern krb5_cc_ops krb5_mcc_ops;
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_authenticate(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Authenticate a user via krb5 */
+int
+pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_ccache ccache, ccache_check;
+ krb5_get_init_creds_opt opts;
+
+ int pamret, i;
+ const char *name;
+ char *source_princ = NULL;
+ char *princ_name = NULL;
+ char *pass = NULL, *service = NULL;
+ char *prompt = NULL;
+ char cache_name[L_tmpnam + 8];
+ char lname[64]; /* local acct name */
+ struct passwd *pw;
+ uid_t ruid;
+
+ int debug = 0, try_first_pass = 0, use_first_pass = 0;
+ int forwardable = 0, reuse_ccache = 0, no_ccache = 0;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "try_first_pass") == 0)
+ try_first_pass = 1;
+ else if (strcmp(argv[i], "use_first_pass") == 0)
+ use_first_pass = 1;
+ else if (strcmp(argv[i], "forwardable") == 0)
+ forwardable = 1;
+ else if (strcmp(argv[i], "reuse_ccache") == 0)
+ reuse_ccache = 1;
+ else if (strcmp(argv[i], "no_ccache") == 0)
+ no_ccache = 1;
+ }
+
+ /* Get username */
+ if ((pamret = pam_get_user(pamh, &name, "login: ")) != PAM_SUCCESS) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+ krb5_get_init_creds_opt_init(&opts);
+ memset(&creds, 0, sizeof(krb5_creds));
+ memset(cache_name, 0, sizeof(cache_name));
+ memset(lname, 0, sizeof(lname));
+
+ if (forwardable)
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
+
+ /* For CNS */
+ if ((krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE)) != 0) {
+ /* Solaris dtlogin doesn't call pam_end() on failure */
+ if (krbret != KRB5_CC_TYPE_EXISTS) {
+ DLOG("krb5_cc_register()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ }
+
+ /* Get principal name */
+ /* This case is for use mainly by su.
+ If non-root is authenticating as "root", use "source_user/root". */
+ if (!strcmp(name, "root") && (ruid = getuid()) != 0) {
+ pw = getpwuid(ruid);
+ if (pw != NULL)
+ source_princ = (char *)malloc(strlen(pw->pw_name) + 6);
+ if (source_princ)
+ sprintf(source_princ, "%s/root", pw->pw_name);
+ } else {
+ source_princ = strdup(name);
+ }
+ if (!source_princ) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+
+ if ((krbret = krb5_parse_name(pam_context, source_princ, &princ)) != 0) {
+ DLOG("krb5_parse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
+ DLOG("krb5_unparse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Get password */
+ prompt = malloc(16 + strlen(princ_name));
+ if (!prompt) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+ (void) sprintf(prompt, "Password for %s: ", princ_name);
+
+ if (try_first_pass || use_first_pass)
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+
+get_pass:
+ if (!pass) {
+ try_first_pass = 0;
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
+ &pass)) != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ /* We have to free pass. */
+ if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ free(pass);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ free(pass);
+ /* Now we get it back from the library. */
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+ }
+
+ /* get a local account name for this principal */
+ if ((krbret = krb5_aname_to_localname(pam_context, princ,
+ sizeof(lname), lname)) == 0) {
+ DLOG("changing PAM_USER to", lname);
+ if ((pamret = pam_set_item(pamh, PAM_USER, lname)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ if ((pamret = pam_get_item(pamh, PAM_USER, (const void **) &name)
+ != 0)) {
+ DLOG("pam_get_item()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ } else {
+ DLOG("krb5_aname_to_localname()", error_message(krbret));
+ /* Not an error. */
+ }
+
+ /* Verify the local user exists (AFTER getting the password) */
+ pw = getpwnam(name);
+ if (!pw) {
+ DLOG("getpwnam()", lname);
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+
+ /* Get a TGT */
+ if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, pam_prompter, pamh, 0, NULL, &opts)) != 0) {
+ DLOG("krb5_get_init_creds_password()", error_message(krbret));
+ if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ pass = NULL;
+ goto get_pass;
+ }
+ pamret = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ /* Generate a unique cache_name */
+ strcpy(cache_name, "MEMORY:");
+ (void) tmpnam(&cache_name[7]);
+
+ if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache)) != 0) {
+ DLOG("krb5_cc_resolve()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ if ((krbret = krb5_cc_initialize(pam_context, ccache, princ)) != 0) {
+ DLOG("krb5_cc_initialize()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ if ((krbret = krb5_cc_store_cred(pam_context, ccache, &creds)) != 0) {
+ DLOG("krb5_cc_store_cred()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ /* Verify it */
+ if (verify_krb_v5_tgt(pam_context, ccache, service, debug) == -1) {
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ /* A successful authentication, store ccache for sm_setcred() */
+ if (!pam_get_data(pamh, "ccache", (const void **) &ccache_check)) {
+ DLOG("pam_get_data()", "ccache data already present");
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ if ((pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache)) != 0) {
+ DLOG("pam_set_data()", pam_strerror(pamh, pamret));
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ if (prompt)
+ free(prompt);
+ if (princ_name)
+ free(princ_name);
+ if (source_princ)
+ free(source_princ);
+
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+}
+
+
+
+/* redefine this for pam_sm_setcred() */
+#undef DLOG
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_setcred(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Called after a successful authentication. Set user credentials. */
+int
+pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_principal princ;
+ krb5_creds creds;
+ krb5_ccache ccache_temp, ccache_perm;
+ krb5_cc_cursor cursor;
+
+ int i, pamret;
+ char *name, *service = NULL;
+ char *cache_name = NULL, *cache_env_name;
+ struct passwd *pw = NULL;
+
+ int debug = 0;
+ uid_t euid;
+ gid_t egid;
+
+ if (flags == PAM_REINITIALIZE_CRED)
+ return PAM_SUCCESS; /* XXX Incorrect behavior */
+
+ if (flags != PAM_ESTABLISH_CRED && flags != PAM_DELETE_CRED)
+ return PAM_SERVICE_ERR;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "no_ccache") == 0)
+ return PAM_SUCCESS;
+ else if (strstr(argv[i], "ccache=") == argv[i])
+ cache_name = (char *) &argv[i][7]; /* save for later */
+ }
+
+ /* Get username */
+ if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+
+ euid = geteuid(); /* Usually 0 */
+ egid = getegid();
+
+ /* Retrieve the cache name */
+ if ((pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp))
+ != 0) {
+ /* User did not use krb5 to login */
+ DLOG("ccache", "not found");
+ pamret = PAM_SUCCESS;
+ goto cleanup3;
+ }
+
+ /* Get the uid. This should exist. */
+ pw = getpwnam(name);
+ if (!pw) {
+ DLOG("getpwnam()", name);
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Avoid following a symlink as root */
+ if (setegid(pw->pw_gid)) {
+ DLOG("setegid()", name); /* XXX should really log group name or id */
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (seteuid(pw->pw_uid)) {
+ DLOG("seteuid()", name);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Get the cache name */
+ if (!cache_name) {
+ cache_name = malloc(64); /* plenty big */
+ if (!cache_name) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ sprintf(cache_name, "FILE:/tmp/krb5cc_%d", pw->pw_uid);
+ } else {
+ /* cache_name was supplied */
+ char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
+ char *q = cache_name;
+ if (!p) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ cache_name = p;
+
+ /* convert %u and %p */
+ while (*q) {
+ if (*q == '%') {
+ q++;
+ if (*q == 'u') {
+ sprintf(p, "%d", pw->pw_uid);
+ p += strlen(p);
+ } else if (*q == 'p') {
+ sprintf(p, "%d", getpid());
+ p += strlen(p);
+ } else {
+ /* Not a special token */
+ *p++ = '%';
+ q--;
+ }
+ q++;
+ } else {
+ *p++ = *q++;
+ }
+ }
+ }
+
+ if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm))
+ != 0) {
+ DLOG("krb5_cc_resolve()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (flags == PAM_ESTABLISH_CRED) {
+ /* Initialize the new ccache */
+ if ((krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ))
+ != 0) {
+ DLOG("krb5_cc_get_principal()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if ((krbret = krb5_cc_initialize(pam_context, ccache_perm, princ)) != 0) {
+ DLOG("krb5_cc_initialize()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Prepare for iteration over creds */
+ if ((krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor))
+ != 0) {
+ DLOG("krb5_cc_start_seq_get()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Copy the creds (should be two of them) */
+ while ((krbret = compat_cc_next_cred(pam_context, ccache_temp,
+ &cursor, &creds) == 0)) {
+ if ((krbret = krb5_cc_store_cred(pam_context, ccache_perm,
+ &creds)) != 0) {
+ DLOG("krb5_cc_store_cred()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ krb5_free_cred_contents(pam_context, &creds);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krb5_free_cred_contents(pam_context, &creds);
+ }
+ (void) krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
+
+ if (strstr(cache_name, "FILE:") == cache_name) {
+ if (chown(&cache_name[5], pw->pw_uid, pw->pw_gid) == -1) {
+ DLOG("chown()", strerror(errno));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ if (chmod(&cache_name[5], (S_IRUSR|S_IWUSR)) == -1) {
+ DLOG("chmod()", strerror(errno));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ }
+ (void) krb5_cc_close(pam_context, ccache_perm);
+
+ cache_env_name = malloc(strlen(cache_name) + 12);
+ if (!cache_env_name) {
+ DLOG("malloc()", "failure");
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+
+ sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
+ if ((pamret = pam_putenv(pamh, cache_env_name)) != 0) {
+ DLOG("pam_putenv()", pam_strerror(pamh, pamret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ } else {
+ /* flag == PAM_DELETE_CRED */
+ if ((krbret = krb5_cc_destroy(pam_context, ccache_perm)) != 0) {
+ /* log error, but otherwise ignore it */
+ DLOG("krb5_cc_destroy()", error_message(krbret));
+ }
+ goto cleanup3;
+ }
+
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ (void) seteuid(euid);
+ (void) setegid(egid);
+ return pamret;
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_pass.c b/lib/libpam/modules/pam_krb5/pam_krb5_pass.c
new file mode 100644
index 000000000000..994c7f4720c6
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_pass.c
@@ -0,0 +1,200 @@
+/*
+ * pam_krb5_pass.c
+ *
+ * PAM password management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_pass.c,v 1.3 1999/01/19 23:43:11 fcusack Exp $";
+
+#include <errno.h>
+#include <stdio.h> /* sprintf */
+#include <stdlib.h> /* malloc */
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_chauthtok(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Change a user's password */
+int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_get_init_creds_opt opts;
+
+ int result_code;
+ krb5_data result_code_string, result_string;
+
+ int pamret, i;
+ char *name, *service = NULL, *pass = NULL, *pass2;
+ char *princ_name = NULL;
+ char *prompt = NULL;
+
+ int debug = 0;
+ int try_first_pass = 0, use_first_pass = 0;
+
+ if (!(flags & PAM_UPDATE_AUTHTOK))
+ return PAM_AUTHTOK_ERR;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "try_first_pass") == 0)
+ try_first_pass = 1;
+ else if (strcmp(argv[i], "use_first_pass") == 0)
+ use_first_pass = 1;
+ }
+
+ /* Get username */
+ if ((pam_get_item(pamh, PAM_USER, (const void **) &name)) != 0) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+ krb5_get_init_creds_opt_init(&opts);
+ memset(&creds, 0, sizeof(krb5_creds));
+
+ /* Get principal name */
+ if ((krbret = krb5_parse_name(pam_context, name, &princ)) != 0) {
+ DLOG("krb5_parse_name()", error_message(krbret));
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
+ DLOG("krb5_unparse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Get password */
+ prompt = malloc(16 + strlen(princ_name));
+ if (!prompt) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+ (void) sprintf(prompt, "Password for %s: ", princ_name);
+
+ if (try_first_pass || use_first_pass)
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+
+get_pass:
+ if (!pass) {
+ try_first_pass = 0;
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
+ &pass)) != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ /* We have to free pass. */
+ if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ free(pass);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ free(pass);
+ /* Now we get it back from the library. */
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+ }
+
+ if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, pam_prompter, pamh, 0, "kadmin/changepw", &opts)) != 0) {
+ DLOG("krb5_get_init_creds_password()", error_message(krbret));
+ if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ pass = NULL;
+ goto get_pass;
+ }
+ pamret = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ /* Now get the new password */
+ free(prompt);
+ prompt = "Enter new password: ";
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))
+ != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ prompt = NULL;
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ prompt = "Enter it again: ";
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2))
+ != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ prompt = NULL;
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ prompt = NULL;
+
+ if (strcmp(pass, pass2) != 0) {
+ DLOG("strcmp()", "passwords not equal");
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ /* Change it */
+ if ((krbret = krb5_change_password(pam_context, &creds, pass,
+ &result_code, &result_code_string, &result_string)) != 0) {
+ DLOG("krb5_change_password()", error_message(krbret));
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+ if (result_code) {
+ DLOG("krb5_change_password() (result_code)", "");
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ if (result_string.data)
+ free(result_string.data);
+ if (result_code_string.data)
+ free(result_code_string.data);
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ if (prompt)
+ free(prompt);
+ if (princ_name)
+ free(princ_name);
+
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_sess.c b/lib/libpam/modules/pam_krb5/pam_krb5_sess.c
new file mode 100644
index 000000000000..b2df06434fa6
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_sess.c
@@ -0,0 +1,28 @@
+/*
+ * pam_krb5_sess.c
+ *
+ * PAM session management functions for pam_krb5
+ * (null functions)
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_sess.c,v 1.3 1999/01/19 20:49:44 fcusack Exp $";
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+/* Initiate session management */
+int
+pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+/* Terminate session management */
+int
+pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
diff --git a/lib/libpam/modules/pam_krb5/support.c b/lib/libpam/modules/pam_krb5/support.c
new file mode 100644
index 000000000000..8e1aecda640f
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/support.c
@@ -0,0 +1,185 @@
+/*
+ * support.c
+ *
+ * Support functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
+
+#include <errno.h>
+#include <stdio.h> /* BUFSIZ */
+#include <stdlib.h> /* malloc */
+#include <string.h> /* strncpy */
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/*
+ * Get info from the user. Disallow null responses (regardless of flags).
+ * response gets allocated and filled in on successful return. Caller
+ * is responsible for freeing it.
+ */
+int
+get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
+{
+ int pamret;
+ struct pam_message msg;
+ const struct pam_message *pmsg;
+ struct pam_response *resp = NULL;
+ struct pam_conv *conv;
+
+ if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
+ return pamret;
+
+ /* set up conversation call */
+ pmsg = &msg;
+ msg.msg_style = type;
+ msg.msg = prompt;
+
+ if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
+ return pamret;
+
+ /* Caller should ignore errors for non-response conversations */
+ if (!resp)
+ return PAM_CONV_ERR;
+
+ if (!(resp->resp && resp->resp[0])) {
+ free(resp);
+ return PAM_AUTH_ERR;
+ }
+
+ *response = resp->resp;
+ free(resp);
+ return pamret;
+}
+
+/*
+ * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
+ * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
+ * for Debian.
+ *
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user. If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC). If the host/<host> service is unknown (i.e.,
+ * the local keytab doesn't have it), and we cannot find another
+ * service we do have, let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+int
+verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
+ char * pam_service, int debug)
+{
+ char phost[BUFSIZ];
+ char *services [3];
+ char **service;
+ krb5_error_code retval = -1;
+ krb5_principal princ;
+ krb5_keyblock * keyblock = 0;
+ krb5_data packet;
+ krb5_auth_context auth_context = NULL;
+
+ packet.data = 0;
+
+ /*
+ * If possible we want to try and verify the ticket we have
+ * received against a keytab. We will try multiple service
+ * principals, including at least the host principal and the PAM
+ * service principal. The host principal is preferred because access
+ * to that key is generally sufficient to compromise root, while the
+ * service key for this PAM service may be less carefully guarded.
+ * It is important to check the keytab first before the KDC so we do
+ * not get spoofed by a fake KDC.*/
+ services [0] = "host";
+ services [1] = pam_service;
+ services [2] = NULL;
+ for ( service = &services[0]; *service != NULL; service++ ) {
+ if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
+ &princ)) != 0) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_sname_to_principal()", error_message(retval));
+ return -1;
+ }
+
+ /* Extract the name directly. */
+ strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
+ phost[BUFSIZ - 1] = '\0';
+
+ /*
+ * Do we have service/<host> keys?
+ * (use default/configured keytab, kvno IGNORE_VNO to get the
+ * first match, and ignore enctype.)
+ */
+ if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
+ 0, &keyblock)) != 0)
+ continue;
+ break;
+ }
+ if (retval != 0 ) { /* failed to find key */
+ /* Keytab or service key does not exist */
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_kt_read_service_key()", error_message(retval));
+ retval = 0;
+ goto cleanup;
+ }
+ if (keyblock)
+ krb5_free_keyblock(context, keyblock);
+
+ /* Talk to the kdc and construct the ticket. */
+ retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
+ NULL, ccache, &packet);
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ auth_context = NULL; /* setup for rd_req */
+ }
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_mk_req()", error_message(retval));
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Try to use the ticket. */
+ retval = krb5_rd_req(context, &auth_context, &packet, princ,
+ NULL, NULL, NULL);
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_rd_req()", error_message(retval));
+ retval = -1;
+ } else {
+ retval = 1;
+ }
+
+cleanup:
+ if (packet.data)
+ compat_free_data_contents(context, &packet);
+ krb5_free_principal(context, princ);
+ return retval;
+
+}
+
+
+/* Free the memory for cache_name. Called by pam_end() */
+void
+cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status)
+{
+ krb5_context pam_context;
+ krb5_ccache ccache;
+
+ if (krb5_init_context(&pam_context))
+ return;
+
+ ccache = (krb5_ccache) data;
+ (void) krb5_cc_destroy(pam_context, ccache);
+ krb5_free_context(pam_context);
+}
diff --git a/release/doc/share/sgml/release.dsl b/release/doc/share/sgml/release.dsl
new file mode 100644
index 000000000000..531a3f5363f3
--- /dev/null
+++ b/release/doc/share/sgml/release.dsl
@@ -0,0 +1,38 @@
+<!-- $FreeBSD$ -->
+
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY freebsd.dsl PUBLIC "-//FreeBSD//DOCUMENT DocBook Stylesheet//EN" CDATA DSSSL>
+]>
+
+<style-sheet>
+ <style-specification use="docbook">
+ <style-specification-body>
+
+; The architecture we're building for. We need to define this as a
+; procedure, because we may not be able to evaluate it until we are
+; at a point in formatting where (current-node) is defined.
+
+(default
+ (let* ((arch (attribute-string (normalize "arch")))
+ (for-arch (entity-text "arch")))
+ (if (or (equal? arch #f)
+ (equal? arch ""))
+ (next-match)
+; We can do a lot more flexible things here. Like it'd be nice to
+; tokenize the arch= attribute and do comparisons of for-arch against
+; different substrings.
+ (cond ((equal? arch for-arch) (next-match))
+ (else (empty-sosofo))))))
+
+; We might have some sect1 level elements where the modification times
+; are significant. An example of this is the "What's New" section in
+; the release notes. We enable the printing of pubdate entry in
+; sect1info elements to support this.
+(element (sect1info pubdate) (process-children))
+
+ </style-specification-body>
+ </style-specification>
+
+ <external-specification id="docbook" document="freebsd.dsl">
+</style-sheet>
+
diff --git a/share/mk/bsd.sys.mk b/share/mk/bsd.sys.mk
new file mode 100644
index 000000000000..566917c4b976
--- /dev/null
+++ b/share/mk/bsd.sys.mk
@@ -0,0 +1,39 @@
+# $FreeBSD$
+#
+# This file contains common settings used for building FreeBSD
+# sources.
+
+# Enable various levels of compiler warning checks. These may be
+# overridden (e.g. if using a non-gcc compiler) by defining NO_WARNS.
+
+.if !defined(NO_WARNS)
+. if defined(WARNS)
+. if ${WARNS} > 0
+CFLAGS += -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith
+# XXX Delete -Wuninitialized by default for now -- the compiler doesn't
+# XXX always get it right.
+CFLAGS += -Wno-uninitialized
+. if !defined(NO_WERROR)
+CFLAGS += -Werror
+. endif
+. endif
+. if ${WARNS} > 1
+CFLAGS += -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow
+. endif
+. endif
+
+. if defined(FORMAT_AUDIT)
+WFORMAT = 1
+. endif
+. if defined(WFORMAT)
+. if ${WFORMAT} > 0
+CFLAGS += -Wnon-const-format -Wno-format-extra-args
+. if !defined(NO_WERROR)
+CFLAGS += -Werror
+. endif
+. endif
+. endif
+.endif
+
+# Allow user-specified additional warning flags
+CFLAGS += ${CWARNFLAGS}
diff --git a/share/monetdef/sk_SK.ISO8859-2.src b/share/monetdef/sk_SK.ISO8859-2.src
new file mode 100644
index 000000000000..dc2ac34f5564
--- /dev/null
+++ b/share/monetdef/sk_SK.ISO8859-2.src
@@ -0,0 +1,38 @@
+# $FreeBSD$
+#
+# Slovak monetary definition by Juraj Bednar <juraj@bednar.sk>
+#
+# WARNING: spaces may be essential at the end of lines
+# WARNING: empty lines are essential too
+#
+# int_curr_symbol (last character always SPACE)
+SKK
+# currency_symbol
+Sk
+# mon_decimal_point
+,
+# mon_thousands_sep
+
+# mon_grouping
+3;3
+# positive_sign
+
+# negative_sign
+-
+# int_frac_digits
+2
+# frac_digits
+2
+# p_cs_precedes
+1
+# p_sep_by_space
+2
+# n_cs_precedes
+1
+# n_sep_by_space
+2
+# p_sign_posn
+4
+# n_sign_posn
+4
+# EOF
diff --git a/share/numericdef/sk_SK.ISO8859-2.src b/share/numericdef/sk_SK.ISO8859-2.src
new file mode 100644
index 000000000000..19776246f8ca
--- /dev/null
+++ b/share/numericdef/sk_SK.ISO8859-2.src
@@ -0,0 +1,14 @@
+# $FreeBSD$
+#
+# Slovak numeric definition
+#
+# WARNING: spaces may be essential at the end of lines
+# WARNING: empty lines are essential too
+#
+# decimal_point
+,
+# thousands_sep
+
+# grouping
+3;3
+# EOF
diff --git a/share/timedef/sk_SK.ISO8859-2.src b/share/timedef/sk_SK.ISO8859-2.src
new file mode 100644
index 000000000000..a10c861f4dd6
--- /dev/null
+++ b/share/timedef/sk_SK.ISO8859-2.src
@@ -0,0 +1,105 @@
+# Slovak month and day names
+# by Juraj Bednar <juraj@bednar.sk>
+#
+# $FreeBSD$
+#
+# WARNING: spaces may be essential at the end of lines
+# WARNING: empty lines are essential too
+#
+# Short months names
+#
+jan
+feb
+mar
+apr
+máj
+jún
+júl
+aug
+sep
+okt
+nov
+dec
+#
+# Long months names
+#
+január
+február
+marec
+apríl
+máj
+jún
+júl
+august
+september
+október
+november
+december
+#
+# Short weekdays names
+#
+ne
+po
+ut
+st
+¹t
+pi
+so
+#
+# Long weekdays names
+#
+nedeµa
+pondelok
+utorok
+streda
+¹tvrtok
+piatok
+sobota
+#
+# X_fmt
+#
+%H:%M:%S
+#
+# x_fmt
+#
+%d.%m.%Y
+#
+# c_fmt
+#
+%a %e %b %X %Y
+#
+# am
+#
+
+#
+# pm
+#
+
+#
+# date_fmt
+#
+%a %e. %B %Y %X %Z
+#
+# Long month names in alternative form
+#
+január
+február
+marec
+apríl
+máj
+jún
+júl
+august
+september
+október
+november
+december
+#
+# md_order
+#
+dm
+#
+# ampm_fmt
+#
+
+# EOF
diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c
new file mode 100644
index 000000000000..b5196c016854
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_vfsops.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * 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 Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+#include "opt_netsmb.h"
+#ifndef NETSMB
+#error "SMBFS requires option NETSMB"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+int smbfs_debuglevel = 0;
+
+static int smbfs_version = SMBFS_VERSION;
+
+#ifdef SMBFS_USEZONE
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+
+vm_zone_t smbfsmount_zone;
+#endif
+
+SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS file system");
+SYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
+SYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, "");
+
+static MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
+
+
+static int smbfs_mount(struct mount *, char *, caddr_t,
+ struct nameidata *, struct proc *);
+static int smbfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
+static int smbfs_root(struct mount *, struct vnode **);
+static int smbfs_start(struct mount *, int, struct proc *);
+static int smbfs_statfs(struct mount *, struct statfs *, struct proc *);
+static int smbfs_sync(struct mount *, int, struct ucred *, struct proc *);
+static int smbfs_unmount(struct mount *, int, struct proc *);
+static int smbfs_init(struct vfsconf *vfsp);
+static int smbfs_uninit(struct vfsconf *vfsp);
+
+#if __FreeBSD_version < 400009
+static int smbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
+static int smbfs_fhtovp(struct mount *, struct fid *,
+ struct sockaddr *, struct vnode **, int *,
+ struct ucred **);
+static int smbfs_vptofh(struct vnode *, struct fid *);
+#endif
+
+static struct vfsops smbfs_vfsops = {
+ smbfs_mount,
+ smbfs_start,
+ smbfs_unmount,
+ smbfs_root,
+ smbfs_quotactl,
+ smbfs_statfs,
+ smbfs_sync,
+#if __FreeBSD_version > 400008
+ vfs_stdvget,
+ vfs_stdfhtovp, /* shouldn't happen */
+ vfs_stdcheckexp,
+ vfs_stdvptofh, /* shouldn't happen */
+#else
+ smbfs_vget,
+ smbfs_fhtovp,
+ smbfs_vptofh,
+#endif
+ smbfs_init,
+ smbfs_uninit,
+#ifndef FB_RELENG3
+ vfs_stdextattrctl,
+#else
+#define M_USE_RESERVE M_KERNEL
+ &sysctl___vfs_smbfs
+#endif
+};
+
+
+VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
+
+MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
+MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
+
+int smbfs_pbuf_freecnt = -1; /* start out unlimited */
+
+static int
+smbfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct smbfs_args args; /* will hold data from mount request */
+ struct smbmount *smp = NULL;
+ struct smb_vc *vcp;
+ struct smb_share *ssp = NULL;
+ struct vnode *vp;
+ struct smb_cred scred;
+#ifndef FB_CURRENT
+ size_t size;
+#endif
+ int error;
+ char *pc, *pe;
+
+ if (data == NULL) {
+ printf("missing data argument\n");
+ return EINVAL;
+ }
+ if (mp->mnt_flag & MNT_UPDATE) {
+ printf("MNT_UPDATE not implemented");
+ return EOPNOTSUPP;
+ }
+ error = copyin(data, (caddr_t)&args, sizeof(struct smbfs_args));
+ if (error)
+ return error;
+ if (args.version != SMBFS_VERSION) {
+ printf("mount version mismatch: kernel=%d, mount=%d\n",
+ SMBFS_VERSION, args.version);
+ return EINVAL;
+ }
+ smb_makescred(&scred, p, p->p_ucred);
+ error = smb_dev2share(args.dev, SMBM_EXEC, &scred, &ssp);
+ if (error) {
+ printf("invalid device handle %d (%d)\n", args.dev, error);
+ return error;
+ }
+ vcp = SSTOVC(ssp);
+ smb_share_unlock(ssp, 0, p);
+ mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
+
+#ifdef SMBFS_USEZONE
+ smp = zalloc(smbfsmount_zone);
+#else
+ MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA, M_USE_RESERVE);
+#endif
+ if (smp == NULL) {
+ printf("could not alloc smbmount\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ bzero(smp, sizeof(*smp));
+ mp->mnt_data = (qaddr_t)smp;
+ smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
+ if (smp->sm_hash == NULL)
+ goto bad;
+ lockinit(&smp->sm_hashlock, PVFS, "smbfsh", 0, 0);
+ smp->sm_share = ssp;
+ smp->sm_root = NULL;
+ smp->sm_args = args;
+ smp->sm_caseopt = args.caseopt;
+ smp->sm_args.file_mode = (smp->sm_args.file_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
+ smp->sm_args.dir_mode = (smp->sm_args.dir_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
+
+/* simple_lock_init(&smp->sm_npslock);*/
+#ifndef FB_CURRENT
+ error = copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ if (error)
+ goto bad;
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+#endif
+ pc = mp->mnt_stat.f_mntfromname;
+ pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
+ bzero(pc, MNAMELEN);
+ *pc++ = '/';
+ *pc++ = '/';
+ pc=index(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
+ if (pc < pe-1) {
+ *(pc++) = '@';
+ pc = index(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
+ if (pc < pe - 1) {
+ *(pc++) = '/';
+ strncpy(pc, ssp->ss_name, pe - pc - 2);
+ }
+ }
+ /* protect against invalid mount points */
+ smp->sm_args.mount_point[sizeof(smp->sm_args.mount_point) - 1] = '\0';
+ vfs_getnewfsid(mp);
+ error = smbfs_root(mp, &vp);
+ if (error)
+ goto bad;
+ VOP_UNLOCK(vp, 0, p);
+ SMBVDEBUG("root.v_usecount = %d\n", vp->v_usecount);
+
+#ifdef DIAGNOSTICS
+ SMBERROR("mp=%p\n", mp);
+#endif
+ return error;
+bad:
+ if (smp) {
+ if (smp->sm_hash)
+ free(smp->sm_hash, M_SMBFSHASH);
+ lockdestroy(&smp->sm_hashlock);
+#ifdef SMBFS_USEZONE
+ zfree(smbfsmount_zone, smp);
+#else
+ free(smp, M_SMBFSDATA);
+#endif
+ }
+ if (ssp)
+ smb_share_put(ssp, &scred);
+ return error;
+}
+
+/* Unmount the filesystem described by mp. */
+static int
+smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct smb_cred scred;
+ int error, flags;
+
+ SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
+ flags = 0;
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+ /* There is 1 extra root vnode reference from smbfs_mount(). */
+ error = vflush(mp, 1, flags);
+ if (error)
+ return error;
+ smb_makescred(&scred, p, p->p_ucred);
+ smb_share_put(smp->sm_share, &scred);
+ mp->mnt_data = (qaddr_t)0;
+
+ if (smp->sm_hash)
+ free(smp->sm_hash, M_SMBFSHASH);
+ lockdestroy(&smp->sm_hashlock);
+#ifdef SMBFS_USEZONE
+ zfree(smbfsmount_zone, smp);
+#else
+ free(smp, M_SMBFSDATA);
+#endif
+ mp->mnt_flag &= ~MNT_LOCAL;
+ return error;
+}
+
+/*
+ * Return locked root vnode of a filesystem
+ */
+static int
+smbfs_root(struct mount *mp, struct vnode **vpp)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct vnode *vp;
+ struct smbnode *np;
+ struct smbfattr fattr;
+ struct proc *p = curproc;
+ struct ucred *cred = p->p_ucred;
+ struct smb_cred scred;
+ int error;
+
+ if (smp == NULL) {
+ SMBERROR("smp == NULL (bug in umount)\n");
+ return EINVAL;
+ }
+ if (smp->sm_root) {
+ *vpp = SMBTOV(smp->sm_root);
+ return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
+ }
+ smb_makescred(&scred, p, cred);
+ error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
+ if (error)
+ return error;
+ error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
+ if (error)
+ return error;
+ vp->v_flag |= VROOT;
+ np = VTOSMB(vp);
+ smp->sm_root = np;
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ * Vfs start routine, a no-op.
+ */
+/* ARGSUSED */
+static int
+smbfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ SMBVDEBUG("flags=%04x\n", flags);
+ return 0;
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+/* ARGSUSED */
+static int
+smbfs_quotactl(mp, cmd, uid, arg, p)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+ SMBVDEBUG("return EOPNOTSUPP\n");
+ return EOPNOTSUPP;
+}
+
+/*ARGSUSED*/
+int
+smbfs_init(struct vfsconf *vfsp)
+{
+#ifndef SMP
+ int name[2];
+ int olen, ncpu, plen, error;
+
+ name[0] = CTL_HW;
+ name[1] = HW_NCPU;
+ error = kernel_sysctl(curproc, name, 2, &ncpu, &olen, NULL, 0, &plen);
+ if (error == 0 && ncpu > 1)
+ printf("warning: smbfs module compiled without SMP support.");
+#endif
+
+#ifdef SMBFS_USEZONE
+ smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
+#endif
+ smbfs_pbuf_freecnt = nswbuf / 2 + 1;
+ SMBVDEBUG("done.\n");
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+smbfs_uninit(struct vfsconf *vfsp)
+{
+
+ SMBVDEBUG("done.\n");
+ return 0;
+}
+
+/*
+ * smbfs_statfs call
+ */
+int
+smbfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct smbnode *np = smp->sm_root;
+ struct smb_share *ssp = smp->sm_share;
+ struct smb_cred scred;
+ int error = 0;
+
+ if (np == NULL)
+ return EINVAL;
+
+ sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */
+ sbp->f_spare2 = 0; /* placeholder */
+ smb_makescred(&scred, p, p->p_ucred);
+
+ if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
+ error = smbfs_smb_statfs2(ssp, sbp, &scred);
+ else
+ error = smbfs_smb_statfs(ssp, sbp, &scred);
+ if (error)
+ return error;
+ sbp->f_flags = 0; /* copy of mount exported flags */
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
+ sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
+ sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return 0;
+}
+
+/*
+ * Flush out the buffer cache
+ */
+/* ARGSUSED */
+static int
+smbfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct vnode *vp;
+ int error, allerror = 0;
+ /*
+ * Force stale buffer cache information to be flushed.
+ */
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = vp->v_mntvnodes.le_next) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
+ goto loop;
+#ifndef FB_RELENG3
+ if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+#else
+ if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+#endif
+ waitfor == MNT_LAZY)
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ error = VOP_FSYNC(vp, cred, waitfor, p);
+ if (error)
+ allerror = error;
+ vput(vp);
+ }
+ return (allerror);
+}
+
+#if __FreeBSD_version < 400009
+/*
+ * smbfs flat namespace lookup. Unsupported.
+ */
+/* ARGSUSED */
+static int smbfs_vget(mp, ino, vpp)
+ struct mount *mp;
+ ino_t ino;
+ struct vnode **vpp;
+{
+ return (EOPNOTSUPP);
+}
+
+/* ARGSUSED */
+static int smbfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
+ struct mount *mp;
+ struct fid *fhp;
+ struct sockaddr *nam;
+ struct vnode **vpp;
+ int *exflagsp;
+ struct ucred **credanonp;
+{
+ return (EINVAL);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen either
+ */
+/* ARGSUSED */
+static int
+smbfs_vptofh(vp, fhp)
+ struct vnode *vp;
+ struct fid *fhp;
+{
+ return (EINVAL);
+}
+
+#endif /* __FreeBSD_version < 400009 */
diff --git a/sys/netsmb/smb_trantcp.c b/sys/netsmb/smb_trantcp.c
new file mode 100644
index 000000000000..3d6b0827b99c
--- /dev/null
+++ b/sys/netsmb/smb_trantcp.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * 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 Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/poll.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+#include <sys/condvar.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <sys/mchain.h>
+
+#include <netsmb/netbios.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_trantcp.h>
+#include <netsmb/smb_subr.h>
+
+#define M_NBDATA M_PCB
+
+static int smb_tcpsndbuf = 10 * 1024;
+static int smb_tcprcvbuf = 10 * 1024;
+
+SYSCTL_DECL(_net_smb);
+SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, "");
+SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, "");
+
+#define nb_sosend(so,m,flags,p) (so)->so_proto->pr_usrreqs->pru_sosend( \
+ so, NULL, 0, m, 0, flags, p)
+
+static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
+ u_int8_t *rpcodep, struct proc *p);
+static int smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p);
+
+static int
+nb_setsockopt_int(struct socket *so, int level, int name, int val)
+{
+ struct sockopt sopt;
+
+ bzero(&sopt, sizeof(sopt));
+ sopt.sopt_level = level;
+ sopt.sopt_name = name;
+ sopt.sopt_val = &val;
+ sopt.sopt_valsize = sizeof(val);
+ return sosetopt(so, &sopt);
+}
+
+static __inline int
+nb_poll(struct nbpcb *nbp, int events, struct proc *p)
+{
+ return nbp->nbp_tso->so_proto->pr_usrreqs->pru_sopoll(nbp->nbp_tso,
+ events, NULL, p);
+}
+
+static int
+nbssn_rselect(struct nbpcb *nbp, struct timeval *tv, int events, struct proc *p)
+{
+ struct timeval atv, rtv, ttv;
+ int timo, error;
+
+ if (tv) {
+ atv = *tv;
+ if (itimerfix(&atv)) {
+ error = EINVAL;
+ goto done_noproclock;
+ }
+ getmicrouptime(&rtv);
+ timevaladd(&atv, &rtv);
+ }
+ timo = 0;
+ PROC_LOCK(p);
+ p->p_flag |= P_SELECT;
+ PROC_UNLOCK(p);
+ error = nb_poll(nbp, events, p);
+ PROC_LOCK(p);
+ if (error) {
+ error = 0;
+ goto done;
+ }
+ if (tv) {
+ getmicrouptime(&rtv);
+ if (timevalcmp(&rtv, &atv, >=)) {
+ /*
+ * An event of our interest may occur during locking a process.
+ * In order to avoid missing the event that occured during locking
+ * the process, test P_SELECT and rescan file descriptors if
+ * necessary.
+ */
+ if ((p->p_flag & P_SELECT) == 0) {
+ p->p_flag |= P_SELECT;
+ PROC_UNLOCK(p);
+ error = nb_poll(nbp, events, p);
+ PROC_LOCK(p);
+ }
+ goto done;
+ }
+ ttv = atv;
+ timevalsub(&ttv, &rtv);
+ timo = tvtohz(&ttv);
+ }
+ p->p_flag &= ~P_SELECT;
+ if (timo > 0)
+ error = cv_timedwait(&selwait, &p->p_mtx, timo);
+ else {
+ cv_wait(&selwait, &p->p_mtx);
+ error = 0;
+ }
+
+done:
+ PROC_UNLOCK(p);
+ p->p_flag &= ~P_SELECT;
+done_noproclock:
+ if (error == ERESTART)
+ return 0;
+ return error;
+}
+
+static int
+nb_intr(struct nbpcb *nbp, struct proc *p)
+{
+ return 0;
+}
+
+static void
+nb_upcall(struct socket *so, void *arg, int waitflag)
+{
+ struct nbpcb *nbp = arg;
+
+ if (arg == NULL || nbp->nbp_selectid == NULL)
+ return;
+ wakeup(nbp->nbp_selectid);
+}
+
+static int
+nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len)
+{
+ u_int32_t *p = mtod(m, u_int32_t *);
+
+ *p = htonl((len & 0x1FFFF) | (type << 24));
+ return 0;
+}
+
+static int
+nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
+{
+ int error;
+ u_char seglen, *cp;
+
+ cp = snb->snb_name;
+ if (*cp == 0)
+ return EINVAL;
+ NBDEBUG("[%s]\n", cp);
+ for (;;) {
+ seglen = (*cp) + 1;
+ error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM);
+ if (error)
+ return error;
+ if (seglen == 1)
+ break;
+ cp += seglen;
+ }
+ return 0;
+}
+
+static int
+nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
+{
+ struct socket *so;
+ int error, s;
+
+ error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, p);
+ if (error)
+ return error;
+ nbp->nbp_tso = so;
+ so->so_upcallarg = (caddr_t)nbp;
+ so->so_upcall = nb_upcall;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ so->so_rcv.sb_timeo = (5 * hz);
+ so->so_snd.sb_timeo = (5 * hz);
+ error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf);
+ if (error)
+ goto bad;
+ nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1);
+ nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1);
+ so->so_rcv.sb_flags &= ~SB_NOINTR;
+ so->so_snd.sb_flags &= ~SB_NOINTR;
+ error = soconnect(so, (struct sockaddr*)to, p);
+ if (error)
+ goto bad;
+ s = splnet();
+ while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
+ tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz);
+ if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 &&
+ (error = nb_intr(nbp, p)) != 0) {
+ so->so_state &= ~SS_ISCONNECTING;
+ splx(s);
+ goto bad;
+ }
+ }
+ if (so->so_error) {
+ error = so->so_error;
+ so->so_error = 0;
+ splx(s);
+ goto bad;
+ }
+ splx(s);
+ return 0;
+bad:
+ smb_nbst_disconnect(nbp->nbp_vc, p);
+ return error;
+}
+
+static int
+nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
+{
+ struct mbchain mb, *mbp = &mb;
+ struct mdchain md, *mdp = &md;
+ struct mbuf *m0;
+ struct timeval tv;
+ struct sockaddr_in sin;
+ u_short port;
+ u_int8_t rpcode;
+ int error, rplen;
+
+ error = mb_init(mbp);
+ if (error)
+ return error;
+ mb_put_uint32le(mbp, 0);
+ nb_put_name(mbp, nbp->nbp_paddr);
+ nb_put_name(mbp, nbp->nbp_laddr);
+ nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
+ error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, p);
+ if (!error) {
+ nbp->nbp_state = NBST_RQSENT;
+ }
+ mb_detach(mbp);
+ mb_done(mbp);
+ if (error)
+ return error;
+ TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo);
+ error = nbssn_rselect(nbp, &tv, POLLIN, p);
+ if (error == EWOULDBLOCK) { /* Timeout */
+ NBDEBUG("initial request timeout\n");
+ return ETIMEDOUT;
+ }
+ if (error) /* restart or interrupt */
+ return error;
+ error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
+ if (error) {
+ NBDEBUG("recv() error %d\n", error);
+ return error;
+ }
+ /*
+ * Process NETBIOS reply
+ */
+ if (m0)
+ md_initm(mdp, m0);
+ error = 0;
+ do {
+ if (rpcode == NB_SSN_POSRESP) {
+ nbp->nbp_state = NBST_SESSION;
+ nbp->nbp_flags |= NBF_CONNECTED;
+ break;
+ }
+ if (rpcode != NB_SSN_RTGRESP) {
+ error = ECONNABORTED;
+ break;
+ }
+ if (rplen != 6) {
+ error = ECONNABORTED;
+ break;
+ }
+ md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
+ md_get_uint16(mdp, &port);
+ sin.sin_port = port;
+ nbp->nbp_state = NBST_RETARGET;
+ smb_nbst_disconnect(nbp->nbp_vc, p);
+ error = nb_connect_in(nbp, &sin, p);
+ if (!error)
+ error = nbssn_rq_request(nbp, p);
+ if (error) {
+ smb_nbst_disconnect(nbp->nbp_vc, p);
+ break;
+ }
+ } while(0);
+ if (m0)
+ md_done(mdp);
+ return error;
+}
+
+static int
+nbssn_recvhdr(struct nbpcb *nbp, int *lenp,
+ u_int8_t *rpcodep, int flags, struct proc *p)
+{
+ struct socket *so = nbp->nbp_tso;
+ struct uio auio;
+ struct iovec aio;
+ u_int32_t len;
+ int error;
+
+ aio.iov_base = (caddr_t)&len;
+ aio.iov_len = sizeof(len);
+ auio.uio_iov = &aio;
+ auio.uio_iovcnt = 1;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_offset = 0;
+ auio.uio_resid = sizeof(len);
+ auio.uio_procp = p;
+ error = so->so_proto->pr_usrreqs->pru_soreceive
+ (so, (struct sockaddr **)NULL, &auio,
+ (struct mbuf **)NULL, (struct mbuf **)NULL, &flags);
+ if (error)
+ return error;
+ if (auio.uio_resid > 0) {
+ SMBSDEBUG("short reply\n");
+ return EPIPE;
+ }
+ len = ntohl(len);
+ *rpcodep = (len >> 24) & 0xFF;
+ len &= 0x1ffff;
+ if (len > SMB_MAXPKTLEN) {
+ SMBERROR("packet too long (%d)\n", len);
+ return EFBIG;
+ }
+ *lenp = len;
+ return 0;
+}
+
+static int
+nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
+ u_int8_t *rpcodep, struct proc *p)
+{
+ struct socket *so = nbp->nbp_tso;
+ struct uio auio;
+ struct mbuf *m;
+ u_int8_t rpcode;
+ int len;
+ int error, rcvflg;
+
+ if (so == NULL)
+ return ENOTCONN;
+
+ if (mpp)
+ *mpp = NULL;
+ for(;;) {
+ m = NULL;
+ error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, p);
+ if (so->so_state &
+ (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) {
+ nbp->nbp_state = NBST_CLOSED;
+ NBDEBUG("session closed by peer\n");
+ return ECONNRESET;
+ }
+ if (error)
+ return error;
+ if (len == 0 && nbp->nbp_state != NBST_SESSION)
+ break;
+ if (rpcode == NB_SSN_KEEPALIVE)
+ continue;
+ bzero(&auio, sizeof(auio));
+ auio.uio_resid = len;
+ auio.uio_procp = p;
+ do {
+ rcvflg = MSG_WAITALL;
+ error = so->so_proto->pr_usrreqs->pru_soreceive
+ (so, (struct sockaddr **)NULL,
+ &auio, &m, (struct mbuf **)NULL, &rcvflg);
+ } while (error == EWOULDBLOCK || error == EINTR ||
+ error == ERESTART);
+ if (error)
+ break;
+ if (auio.uio_resid > 0) {
+ SMBERROR("packet is shorter than expected\n");
+ error = EPIPE;
+ break;
+ }
+ if (nbp->nbp_state == NBST_SESSION &&
+ rpcode == NB_SSN_MESSAGE)
+ break;
+ NBDEBUG("non-session packet %x\n", rpcode);
+ if (m)
+ m_freem(m);
+ }
+ if (error) {
+ if (m)
+ m_freem(m);
+ return error;
+ }
+ if (mpp)
+ *mpp = m;
+ else
+ m_freem(m);
+ *lenp = len;
+ *rpcodep = rpcode;
+ return 0;
+}
+
+/*
+ * SMB transport interface
+ */
+static int
+smb_nbst_create(struct smb_vc *vcp, struct proc *p)
+{
+ struct nbpcb *nbp;
+
+ MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK);
+ bzero(nbp, sizeof *nbp);
+ nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */
+ nbp->nbp_state = NBST_CLOSED;
+ nbp->nbp_vc = vcp;
+ nbp->nbp_sndbuf = smb_tcpsndbuf;
+ nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ vcp->vc_tdata = nbp;
+ return 0;
+}
+
+static int
+smb_nbst_done(struct smb_vc *vcp, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+
+ if (nbp == NULL)
+ return ENOTCONN;
+ smb_nbst_disconnect(vcp, p);
+ if (nbp->nbp_laddr)
+ free(nbp->nbp_laddr, M_SONAME);
+ if (nbp->nbp_paddr)
+ free(nbp->nbp_paddr, M_SONAME);
+ free(nbp, M_NBDATA);
+ return 0;
+}
+
+static int
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ struct sockaddr_nb *snb;
+ int error, slen;
+
+ NBDEBUG("\n");
+ error = EINVAL;
+ do {
+ if (nbp->nbp_flags & NBF_LOCADDR)
+ break;
+ /*
+ * It is possible to create NETBIOS name in the kernel,
+ * but nothing prevents us to do it in the user space.
+ */
+ if (sap == NULL)
+ break;
+ slen = sap->sa_len;
+ if (slen < NB_MINSALEN)
+ break;
+ snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
+ if (snb == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ nbp->nbp_laddr = snb;
+ nbp->nbp_flags |= NBF_LOCADDR;
+ error = 0;
+ } while(0);
+ return error;
+}
+
+static int
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ struct sockaddr_in sin;
+ struct sockaddr_nb *snb;
+ struct timespec ts1, ts2;
+ int error, slen;
+
+ NBDEBUG("\n");
+ if (nbp->nbp_tso != NULL)
+ return EISCONN;
+ if (nbp->nbp_laddr == NULL)
+ return EINVAL;
+ slen = sap->sa_len;
+ if (slen < NB_MINSALEN)
+ return EINVAL;
+ if (nbp->nbp_paddr) {
+ free(nbp->nbp_paddr, M_SONAME);
+ nbp->nbp_paddr = NULL;
+ }
+ snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
+ if (snb == NULL)
+ return ENOMEM;
+ nbp->nbp_paddr = snb;
+ sin = snb->snb_addrin;
+ getnanotime(&ts1);
+ error = nb_connect_in(nbp, &sin, p);
+ if (error)
+ return error;
+ getnanotime(&ts2);
+ timespecsub(&ts2, &ts1);
+ if (ts2.tv_sec == 0 && ts2.tv_sec == 0)
+ ts2.tv_sec = 1;
+ nbp->nbp_timo = ts2;
+ timespecadd(&nbp->nbp_timo, &ts2);
+ timespecadd(&nbp->nbp_timo, &ts2);
+ timespecadd(&nbp->nbp_timo, &ts2); /* * 4 */
+ error = nbssn_rq_request(nbp, p);
+ if (error)
+ smb_nbst_disconnect(vcp, p);
+ return error;
+}
+
+static int
+smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ struct socket *so;
+
+ if (nbp == NULL || nbp->nbp_tso == NULL)
+ return ENOTCONN;
+ if ((so = nbp->nbp_tso) != NULL) {
+ nbp->nbp_flags &= ~NBF_CONNECTED;
+ nbp->nbp_tso = (struct socket *)NULL;
+ soshutdown(so, 2);
+ soclose(so);
+ }
+ if (nbp->nbp_state != NBST_RETARGET) {
+ nbp->nbp_state = NBST_CLOSED;
+ }
+ return 0;
+}
+
+static int
+smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ int error;
+
+ if (nbp->nbp_state != NBST_SESSION) {
+ error = ENOTCONN;
+ goto abort;
+ }
+ M_PREPEND(m0, 4, M_WAITOK);
+ if (m0 == NULL)
+ return ENOBUFS;
+ nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4);
+ error = nb_sosend(nbp->nbp_tso, m0, 0, p);
+ return error;
+abort:
+ if (m0)
+ m_freem(m0);
+ return error;
+}
+
+
+static int
+smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct proc *p)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ u_int8_t rpcode;
+ int error, rplen;
+
+ nbp->nbp_flags |= NBF_RECVLOCK;
+ error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
+ nbp->nbp_flags &= ~NBF_RECVLOCK;
+ return error;
+}
+
+static void
+smb_nbst_timo(struct smb_vc *vcp)
+{
+ return;
+}
+
+static void
+smb_nbst_intr(struct smb_vc *vcp)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+
+ if (nbp == NULL || nbp->nbp_tso == NULL)
+ return;
+ sorwakeup(nbp->nbp_tso);
+ sowwakeup(nbp->nbp_tso);
+}
+
+static int
+smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+
+ switch (param) {
+ case SMBTP_SNDSZ:
+ *(int*)data = nbp->nbp_sndbuf;
+ break;
+ case SMBTP_RCVSZ:
+ *(int*)data = nbp->nbp_rcvbuf;
+ break;
+ case SMBTP_TIMEOUT:
+ *(struct timespec*)data = nbp->nbp_timo;
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct nbpcb *nbp = vcp->vc_tdata;
+
+ switch (param) {
+ case SMBTP_SELECTID:
+ nbp->nbp_selectid = data;
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Check for fatal errors
+ */
+static int
+smb_nbst_fatal(struct smb_vc *vcp, int error)
+{
+ switch (error) {
+ case ENOTCONN:
+ case ENETRESET:
+ case ECONNABORTED:
+ return 1;
+ }
+ return 0;
+}
+
+
+struct smb_tran_desc smb_tran_nbtcp_desc = {
+ SMBT_NBTCP,
+ smb_nbst_create, smb_nbst_done,
+ smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect,
+ smb_nbst_send, smb_nbst_recv,
+ smb_nbst_timo, smb_nbst_intr,
+ smb_nbst_getparam, smb_nbst_setparam,
+ smb_nbst_fatal
+};
+
diff --git a/sys/pccard/mecia.c b/sys/pccard/mecia.c
new file mode 100644
index 000000000000..76669c8ea9d3
--- /dev/null
+++ b/sys/pccard/mecia.c
@@ -0,0 +1,730 @@
+/*
+ * NEC MECIA controller.
+ *-------------------------------------------------------------------------
+ *
+ * Copyright (c) 2001 M. Warner Losh. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * $FreeBSD$
+ *
+ * Based heavily on the FreeBSD pcic driver's pcic98 support, derived
+ * from PAO3 tree. This copyright notice likely needs modification for
+ * such a linage. The only authorship I could find was:
+ *
+ * PC9801 original PCMCIA controller code for NS/A,Ne,NX/C,NR/L.
+ * by Noriyuki Hosobuchi <hoso@ce.mbn.or.jp>
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <pccard/meciareg.h>
+#include <pccard/cardinfo.h>
+#include <pccard/slot.h>
+#ifndef MECIA_IOBASE
+#define MECIA_IOBASE 0x80d0
+#endif
+
+/* Get pnp IDs */
+#include <isa/isavar.h>
+
+#include <dev/pccard/pccardvar.h>
+#include "card_if.h"
+
+#define MECIA_DEVICE2SOFTC(dev) ((struct mecia_slot *) device_get_softc(dev))
+
+/*
+ * Prototypes for interrupt handler.
+ */
+static driver_intr_t meciaintr;
+static int mecia_ioctl(struct slot *, int, caddr_t);
+static int mecia_power(struct slot *);
+static void mecia_mapirq(struct slot *, int);
+static timeout_t mecia_reset;
+static void mecia_resume(struct slot *);
+static void mecia_disable(struct slot *);
+static timeout_t meciatimeout;
+static struct callout_handle meciatimeout_ch
+ = CALLOUT_HANDLE_INITIALIZER(&meciatimeout_ch);
+static int mecia_memory(struct slot *, int);
+static int mecia_io(struct slot *, int);
+
+/*
+ * Per-slot data table.
+ */
+struct mecia_slot {
+ int unit; /* Unit number */
+ int slotnum; /* My slot number */
+ struct slot *slt; /* Back ptr to slot */
+ device_t dev; /* My device */
+ u_char last_reg1; /* Last value of change reg */
+};
+
+static struct slot_ctrl mecia_cinfo = {
+ mecia_mapirq,
+ mecia_memory,
+ mecia_io,
+ mecia_reset,
+ mecia_disable,
+ mecia_power,
+ mecia_ioctl,
+ mecia_resume,
+ 1,
+#if 0
+ 1
+#else
+ 2 /* Fake for UE2212 LAN card */
+#endif
+};
+
+static int validunits = 0;
+
+/*
+ * Look for an NEC MECIA.
+ * For each available slot, allocate a PC-CARD slot.
+ */
+
+static int
+mecia_probe(device_t dev)
+{
+ int validslots = 0;
+
+ /* Check isapnp ids */
+ if (isa_get_logicalid(dev)) /* skip PnP probes */
+ return (ENXIO);
+
+ if (inb(MECIA_REG0) != 0xff) {
+ validslots++;
+ /* XXX need to allocated the port resources */
+ device_set_desc(dev, "MECIA PC98 Original PCMCIA Controller");
+ }
+ return (validslots ? 0 : ENXIO);
+}
+
+static int
+mecia_attach(device_t dev)
+{
+ int error;
+ int irq;
+ void *ih;
+ device_t kid;
+ struct resource *r;
+ int rid;
+ struct slot *slt;
+ struct mecia_slot *sp;
+
+ sp = MECIA_DEVICE2SOFTC(dev);
+ sp->unit = validunits++;
+ kid = device_add_child(dev, NULL, -1);
+ if (kid == NULL) {
+ device_printf(dev, "Can't add pccard bus slot 0\n");
+ return (ENXIO);
+ }
+ device_probe_and_attach(kid);
+ slt = pccard_init_slot(kid, &mecia_cinfo);
+ if (slt == 0) {
+ device_printf(dev, "Can't get pccard info slot 0\n");
+ return (ENXIO);
+ }
+ slt->cdata = sp;
+ sp->slt = slt;
+ validunits++;
+
+ rid = 0;
+ r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
+ if (!r)
+ return (ENXIO);
+
+ irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
+ if (irq == 0) {
+ /* See if the user has requested a specific IRQ */
+ if (!getenv_int("machdep.pccard.mecia_irq", &irq))
+ irq = 0;
+ }
+ rid = 0;
+ r = 0;
+ if (irq > 0) {
+ r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
+ irq, 1, RF_ACTIVE);
+ }
+ if (r && ((1 << (rman_get_start(r))) & MECIA_INT_MASK_ALLOWED) == 0) {
+ device_printf(dev,
+ "Hardware does not support irq %d, trying polling.\n",
+ irq);
+ bus_release_resource(dev, SYS_RES_IRQ, rid, r);
+ r = 0;
+ irq = 0;
+ }
+ if (r) {
+ error = bus_setup_intr(dev, r, INTR_TYPE_MISC,
+ meciaintr, (void *) sp, &ih);
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, r);
+ return (error);
+ }
+ irq = rman_get_start(r);
+ device_printf(dev, "management irq %d\n", irq);
+ } else {
+ irq = 0;
+ }
+ if (irq == 0) {
+ meciatimeout_ch = timeout(meciatimeout, (void *) sp, hz/2);
+ device_printf(dev, "Polling mode\n");
+ }
+
+ sp->last_reg1 = inb(MECIA_REG1);
+ if (sp->last_reg1 & MECIA_CARDEXIST) {
+ /* PCMCIA card exist */
+ sp->slt->laststate = sp->slt->state = filled;
+ pccard_event(sp->slt, card_inserted);
+ } else {
+ sp->slt->laststate = sp->slt->state = empty;
+ }
+ sp->slt->irq = irq;
+
+ return (bus_generic_attach(dev));
+}
+
+/*
+ * ioctl calls - Controller specific ioctls
+ */
+static int
+mecia_ioctl(struct slot *slt, int cmd, caddr_t data)
+{
+ return (ENOTTY);
+}
+
+/*
+ * MECIA timer. If the controller doesn't have a free IRQ to use
+ * or if interrupt steering doesn't work, poll the controller for
+ * insertion/removal events.
+ */
+static void
+meciatimeout(void *chan)
+{
+ meciaintr(chan);
+ meciatimeout_ch = timeout(meciatimeout, chan, hz/2);
+}
+
+/*
+ * MECIA Interrupt handler.
+ * Check the slot and report any changes.
+ */
+static void
+meciaintr(void *arg)
+{
+ u_char reg1;
+ int s;
+ struct mecia_slot *sp = (struct mecia_slot *) arg;
+
+ s = splhigh();
+ /* Check for a card in this slot */
+ reg1 = inb(MECIA_REG1);
+ if ((sp->last_reg1 ^ reg1) & MECIA_CARDEXIST) {
+ sp->last_reg1 = reg1;
+ if (reg1 & MECIA_CARDEXIST)
+ pccard_event(sp->slt, card_inserted);
+ else
+ pccard_event(sp->slt, card_removed);
+ }
+ splx(s);
+}
+
+/*
+ * local functions for PC-98 Original PC-Card controller
+ */
+#define MECIA_ALWAYS_128MAPPING 1 /* trick for using UE2212 */
+
+int mecia_mode = 0; /* almost the same as the value in MECIA_REG2 */
+
+static unsigned char reg_winsel = MECIA_UNMAPWIN;
+static unsigned short reg_pagofs = 0;
+
+static int
+mecia_memory(struct slot *slt, int win)
+{
+ struct mem_desc *mp = &slt->mem[win];
+ unsigned char x;
+
+ if (mp->flags & MDF_ACTIVE) {
+ /* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */
+ if ((unsigned long)mp->start != 0xda000) {
+ printf(
+ "sys_addr must be 0xda000. requested address = %p\n",
+ mp->start);
+ return (EINVAL);
+ }
+
+ /* omajinai ??? */
+ outb(MECIA_REG0, 0);
+ x = inb(MECIA_REG1);
+ x &= 0xfc;
+ x |= 0x02;
+ outb(MECIA_REG1, x);
+ reg_winsel = inb(MECIA_REG_WINSEL);
+ reg_pagofs = inw(MECIA_REG_PAGOFS);
+ outb(MECIA_REG_WINSEL, MECIA_MAPWIN);
+ outw(MECIA_REG_PAGOFS, (mp->card >> 13)); /* 8KB */
+
+ if (mp->flags & MDF_ATTR)
+ outb(MECIA_REG7, inb(MECIA_REG7) | MECIA_ATTRMEM);
+ else
+ outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_ATTRMEM));
+
+ outb(MECIA_REG_WINSEL, MECIA_MAPWIN);
+#if 0
+ if ((mp->flags & MDF_16BITS) == 1) /* 16bit */
+ outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_8BIT));
+ else /* 8bit */
+ outb(MECIA_REG2, inb(MECIA_REG2) | MECIA_8BIT);
+#endif
+ } else { /* !(mp->flags & MDF_ACTIVE) */
+ outb(MECIA_REG0, 0);
+ x = inb(MECIA_REG1);
+ x &= 0xfc;
+ x |= 0x02;
+ outb(MECIA_REG1, x);
+#if 0
+ outb(MECIA_REG_WINSEL, MECIA_UNMAPWIN);
+ outw(MECIA_REG_PAGOFS, 0);
+#else
+ outb(MECIA_REG_WINSEL, reg_winsel);
+ outw(MECIA_REG_PAGOFS, reg_pagofs);
+#endif
+ }
+ return (0);
+}
+
+static int
+mecia_io(struct slot *slt, int win)
+{
+ struct io_desc *ip = &slt->io[win];
+ unsigned char x;
+ unsigned short cardbase;
+ u_short ofst;
+
+ if (win != 0) {
+ /* ignore for UE2212 */
+ printf(
+ "mecia:Illegal MECIA I/O window(%d) request! Ignored.\n", win);
+/* return (EINVAL);*/
+ return (0);
+ }
+
+ if (ip->flags & IODF_ACTIVE) {
+ x = inb(MECIA_REG2) & 0x0f;
+#if 0
+ if (! (ip->flags & IODF_CS16))
+ x |= MECIA_8BIT;
+#else
+ if (! (ip->flags & IODF_16BIT)) {
+ x |= MECIA_8BIT;
+ mecia_mode |= MECIA_8BIT;
+ }
+#endif
+
+ ofst = ip->start & 0xf;
+ cardbase = ip->start & ~0xf;
+#ifndef MECIA_ALWAYS_128MAPPING
+ if (ip->size + ofst > 16)
+#endif
+ { /* 128bytes mapping */
+ x |= MECIA_MAP128;
+ mecia_mode |= MECIA_MAP128;
+ ofst |= ((cardbase & 0x70) << 4);
+ cardbase &= ~0x70;
+ }
+
+ x |= MECIA_MAPIO;
+ outb(MECIA_REG2, x);
+
+ outw(MECIA_REG4, MECIA_IOBASE); /* 98side I/O base */
+ outw(MECIA_REG5, cardbase); /* card side I/O base */
+
+ if (bootverbose) {
+ printf("mecia: I/O mapped 0x%04x(98) -> "
+ "0x%04x(Card) and width %d bytes\n",
+ MECIA_IOBASE+ofst, ip->start, ip->size);
+ printf("mecia: reg2=0x%02x reg3=0x%02x reg7=0x%02x\n",
+ inb(MECIA_REG2), inb(MECIA_REG3),
+ inb(MECIA_REG7));
+ printf("mecia: mode=%d\n", mecia_mode);
+ }
+
+ ip->start = MECIA_IOBASE + ofst;
+ } else {
+ outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO));
+ mecia_mode = 0;
+ }
+ return (0);
+}
+
+static int
+mecia_power(struct slot *slt)
+{
+ unsigned char reg;
+
+ reg = inb(MECIA_REG7) & (~MECIA_VPP12V);
+ switch(slt->pwr.vpp) {
+ default:
+ return (EINVAL);
+ case 50:
+ break;
+ case 120:
+ reg |= MECIA_VPP12V;
+ break;
+ }
+ outb(MECIA_REG7, reg);
+ DELAY(100*1000);
+
+ reg = inb(MECIA_REG2) & (~MECIA_VCC3P3V);
+ switch(slt->pwr.vcc) {
+ default:
+ return (EINVAL);
+ case 33:
+ reg |= MECIA_VCC3P3V;
+ break;
+ case 50:
+ break;
+ }
+ outb(MECIA_REG2, reg);
+ DELAY(100*1000);
+ return (0);
+}
+
+static void
+mecia_mapirq(struct slot *slt, int irq)
+{
+ u_char x;
+
+ switch (irq) {
+ case 3:
+ x = MECIA_INT0;
+ break;
+ case 5:
+ x = MECIA_INT1;
+ break;
+ case 6:
+ x = MECIA_INT2;
+ break;
+ case 10:
+ x = MECIA_INT4;
+ break;
+ case 12:
+ x = MECIA_INT5;
+ break;
+ case 0: /* disable */
+ x = MECIA_INTDISABLE;
+ break;
+ default:
+ printf("mecia: illegal irq %d\n", irq);
+ return;
+ }
+#ifdef MECIA_DEBUG
+ printf("mecia: irq=%d mapped.\n", irq);
+#endif
+ outb(MECIA_REG3, x);
+}
+
+static void
+mecia_reset(void *chan)
+{
+ struct slot *slt = chan;
+
+ outb(MECIA_REG0, 0);
+ outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO));
+ outb(MECIA_REG3, MECIA_INTDISABLE);
+#if 0
+/* mecia_reset() is called after mecia_power() */
+ outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_VCC3P3V));
+ outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_VPP12V));
+#endif
+ outb(MECIA_REG1, 0);
+
+ selwakeup(&slt->selp);
+}
+
+static void
+mecia_disable(struct slot *slt)
+{
+ /* null function */
+}
+
+static void
+mecia_resume(struct slot *slt)
+{
+ /* XXX MECIA How ? */
+}
+
+static int
+mecia_activate_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ int err;
+
+ if (dev != device_get_parent(device_get_parent(child)) || devi == NULL)
+ return (bus_generic_activate_resource(dev, child, type,
+ rid, r));
+
+ switch (type) {
+ case SYS_RES_IOPORT: {
+ struct io_desc *ip;
+ ip = &devi->slt->io[rid];
+ if (ip->flags == 0) {
+ if (rid == 0)
+ ip->flags = IODF_WS | IODF_16BIT | IODF_CS16;
+ else
+ ip->flags = devi->slt->io[0].flags;
+ }
+ ip->flags |= IODF_ACTIVE;
+ ip->start = rman_get_start(r);
+ ip->size = rman_get_end(r) - rman_get_start(r) + 1;
+ err = mecia_cinfo.mapio(devi->slt, rid);
+ if (err)
+ return (err);
+ break;
+ }
+ case SYS_RES_IRQ:
+ /*
+ * We actually defer the activation of the IRQ resource
+ * until the interrupt is registered to avoid stray
+ * interrupt messages.
+ */
+ break;
+ case SYS_RES_MEMORY: {
+ struct mem_desc *mp;
+ if (rid >= NUM_MEM_WINDOWS)
+ return (EINVAL);
+ mp = &devi->slt->mem[rid];
+ mp->flags |= MDF_ACTIVE;
+ mp->start = (caddr_t) rman_get_start(r);
+ mp->size = rman_get_end(r) - rman_get_start(r) + 1;
+ err = mecia_cinfo.mapmem(devi->slt, rid);
+ if (err)
+ return (err);
+ break;
+ }
+ default:
+ break;
+ }
+ err = bus_generic_activate_resource(dev, child, type, rid, r);
+ return (err);
+}
+
+static int
+mecia_deactivate_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ int err;
+
+ if (dev != device_get_parent(device_get_parent(child)) || devi == NULL)
+ return (bus_generic_deactivate_resource(dev, child, type,
+ rid, r));
+
+ switch (type) {
+ case SYS_RES_IOPORT: {
+ struct io_desc *ip = &devi->slt->io[rid];
+ ip->flags &= ~IODF_ACTIVE;
+ err = mecia_cinfo.mapio(devi->slt, rid);
+ if (err)
+ return (err);
+ break;
+ }
+ case SYS_RES_IRQ:
+ break;
+ case SYS_RES_MEMORY: {
+ struct mem_desc *mp = &devi->slt->mem[rid];
+ mp->flags &= ~(MDF_ACTIVE | MDF_ATTR);
+ err = mecia_cinfo.mapmem(devi->slt, rid);
+ if (err)
+ return (err);
+ break;
+ }
+ default:
+ break;
+ }
+ err = bus_generic_deactivate_resource(dev, child, type, rid, r);
+ return (err);
+}
+
+static int
+mecia_setup_intr(device_t dev, device_t child, struct resource *irq,
+ int flags, driver_intr_t *intr, void *arg, void **cookiep)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ int err;
+
+ if (((1 << rman_get_start(irq)) & MECIA_INT_MASK_ALLOWED) == 0) {
+ device_printf(dev, "Hardware does not support irq %ld.\n",
+ rman_get_start(irq));
+ return (EINVAL);
+ }
+
+ err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg,
+ cookiep);
+ if (err == 0)
+ mecia_cinfo.mapirq(devi->slt, rman_get_start(irq));
+ else
+ device_printf(dev, "Error %d irq %ld\n", err,
+ rman_get_start(irq));
+ return (err);
+}
+
+static int
+mecia_teardown_intr(device_t dev, device_t child, struct resource *irq,
+ void *cookie)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+
+ mecia_cinfo.mapirq(devi->slt, 0);
+ return (bus_generic_teardown_intr(dev, child, irq, cookie));
+}
+
+static int
+mecia_set_res_flags(device_t bus, device_t child, int restype, int rid,
+ u_long value)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ int err = 0;
+
+ switch (restype) {
+ case SYS_RES_MEMORY: {
+ struct mem_desc *mp = &devi->slt->mem[rid];
+ switch (value) {
+ case PCCARD_A_MEM_COM:
+ mp->flags &= ~MDF_ATTR;
+ break;
+ case PCCARD_A_MEM_ATTR:
+ mp->flags |= MDF_ATTR;
+ break;
+ case PCCARD_A_MEM_8BIT:
+ mp->flags &= ~MDF_16BITS;
+ break;
+ case PCCARD_A_MEM_16BIT:
+ mp->flags |= MDF_16BITS;
+ break;
+ }
+ err = mecia_cinfo.mapmem(devi->slt, rid);
+ break;
+ }
+ default:
+ err = EOPNOTSUPP;
+ }
+ return (err);
+}
+
+static int
+mecia_get_res_flags(device_t bus, device_t child, int restype, int rid,
+ u_long *value)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ int err = 0;
+
+ if (value == 0)
+ return (ENOMEM);
+
+ switch (restype) {
+ case SYS_RES_IOPORT: {
+ struct io_desc *ip = &devi->slt->io[rid];
+ *value = ip->flags;
+ break;
+ }
+ case SYS_RES_MEMORY: {
+ struct mem_desc *mp = &devi->slt->mem[rid];
+ *value = mp->flags;
+ break;
+ }
+ default:
+ err = EOPNOTSUPP;
+ }
+ return (err);
+}
+
+static int
+mecia_set_memory_offset(device_t bus, device_t child, int rid,
+ u_int32_t offset, u_int32_t *deltap)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ struct mem_desc *mp = &devi->slt->mem[rid];
+
+ mp->card = offset;
+ if (deltap)
+ *deltap = 0; /* XXX BAD XXX */
+ return (mecia_cinfo.mapmem(devi->slt, rid));
+}
+
+static int
+mecia_get_memory_offset(device_t bus, device_t child, int rid,
+ u_int32_t *offset)
+{
+ struct pccard_devinfo *devi = device_get_ivars(child);
+ struct mem_desc *mp = &devi->slt->mem[rid];
+
+ if (offset == 0)
+ return (ENOMEM);
+
+ *offset = mp->card;
+
+ return (0);
+}
+
+static device_method_t mecia_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mecia_probe),
+ DEVMETHOD(device_attach, mecia_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, mecia_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, mecia_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, mecia_setup_intr),
+ DEVMETHOD(bus_teardown_intr, mecia_teardown_intr),
+
+ /* Card interface */
+ DEVMETHOD(card_set_res_flags, mecia_set_res_flags),
+ DEVMETHOD(card_get_res_flags, mecia_get_res_flags),
+ DEVMETHOD(card_set_memory_offset, mecia_set_memory_offset),
+ DEVMETHOD(card_get_memory_offset, mecia_get_memory_offset),
+
+ { 0, 0 }
+};
+
+devclass_t mecia_devclass;
+
+static driver_t mecia_driver = {
+ "mecia",
+ mecia_methods,
+ sizeof(struct mecia_slot)
+};
+
+DRIVER_MODULE(mecia, isa, mecia_driver, mecia_devclass, 0, 0);
diff --git a/sys/pccard/meciareg.h b/sys/pccard/meciareg.h
new file mode 100644
index 000000000000..b54ae4d61843
--- /dev/null
+++ b/sys/pccard/meciareg.h
@@ -0,0 +1,60 @@
+/*
+ * meciareg.h
+ *
+ * PC9801 original PCMCIA controller code for NS/A,Ne,NX/C,NR/L.
+ * by Noriyuki Hosobuchi <hoso@ce.mbn.or.jp>
+ *
+ * $FreeBSD$
+ */
+
+/*--- I/O port definition */
+#define MECIA_REG0 0x0a8e /* byte */
+#define MECIA_REG1 0x1a8e /* byte */
+#define MECIA_REG2 0x2a8e /* byte */
+#define MECIA_REG3 0x3a8e /* byte : Interrupt */
+#define MECIA_REG4 0x4a8e /* word : PC98 side I/O base */
+#define MECIA_REG5 0x5a8e /* word : Card side I/O base */
+#define MECIA_REG7 0x7a8e /* byte */
+
+#define MECIA_REG_WINSEL 0x1e8e /* byte : win bank select register */
+#define MECIA_REG_PAGOFS 0x0e8e /* word */
+
+/* PC98_REG_WINSEL */
+#define MECIA_MAPWIN 0x84 /* map Card on 0xda0000 - 0xdbffff */
+#define MECIA_UNMAPWIN 0x00
+
+/* MECIA_REG1 */
+#define MECIA_CARDEXIST 0x08 /* 1:exist 0:not exist */
+
+/* MECIA_REG2 */
+#define MECIA_MAPIO 0x80 /* 1:I/O 0:Memory */
+#define MECIA_IOTHROUGH 0x40 /* 0:I/O map 1:I/O addr-through */
+#define MECIA_8BIT 0x20 /* bit width 1:8bit 0:16bit */
+#define MECIA_MAP128 0x10 /* I/O map size 1:128byte 0:16byte */
+#define MECIA_VCC3P3V 0x02 /* Vcc 1:3.3V 0:5.0V */
+
+/* MECIA_REG3 */
+#define MECIA_INT0 (0xf8 + 0x0) /* INT0(IRQ3) */
+#define MECIA_INT1 (0xf8 + 0x1) /* INT1(IRQ5) */
+#define MECIA_INT2 (0xf8 + 0x2) /* INT2(IRQ6) */
+#define MECIA_INT4 (0xf8 + 0x4) /* INT4(IRQ10) */
+#define MECIA_INT5 (0xf8 + 0x5) /* INT5(IRQ12) */
+#define MECIA_INTDISABLE (0xf8 + 0x7) /* disable interrupt */
+
+/* MECIA_REG7 */
+#define MECIA_ATTRMEM 0x20 /* 1:attr mem 0:common mem */
+#define MECIA_VPP12V 0x10 /* Vpp 0:5V 1:12V */
+
+
+#ifdef KERNEL
+extern int mecia_mode; /* in 'pccard/pcic.c' */
+#define mecia_8bit_on() \
+ if (mecia_mode & MECIA_8BIT) \
+ outb(MECIA_REG2, inb(MECIA_REG2) | MECIA_8BIT)
+#define mecia_8bit_off() \
+ if (mecia_mode & MECIA_8BIT) \
+ outb(MECIA_REG2, inb(MECIA_REG2) & ~MECIA_8BIT)
+#define mecia_map128() (mecia_mode & MECIA_MAP128)
+#endif
+
+#define MECIA_INT_MASK_ALLOWED 0x3E68 /* PC98 */