summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/restart_scripts/renew_ca_cert59
-rw-r--r--install/restart_scripts/renew_ra_cert70
-rw-r--r--install/tools/ipa-upgradeconfig4
-rw-r--r--ipaserver/install/cainstance.py37
4 files changed, 51 insertions, 119 deletions
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
index b05369cbe..9b1b45d87 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -2,8 +2,9 @@
#
# Authors:
# Rob Crittenden <rcritten@redhat.com>
+# Jan Cholasta <jcholast@redhat.com>
#
-# Copyright (C) 2012 Red Hat
+# Copyright (C) 2013 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
@@ -19,29 +20,18 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
import sys
-import shutil
-import tempfile
+import os
import syslog
-import random
-import time
+import tempfile
+import shutil
import traceback
-from ipalib import api
-from ipapython.dn import DN
-from ipalib import errors
+
+from ipapython import dogtag, certmonger, ipautil
from ipapython import services as ipaservices
-from ipapython import ipautil
-from ipapython import dogtag
-from ipaserver.install import certs
-from ipaserver.install.cainstance import update_people_entry
+from ipalib import api, errors, x509, util
+from ipaserver.install import certs, cainstance, installutils
from ipaserver.plugins.ldap2 import ldap2
-from ipaserver.install.cainstance import update_cert_config
-from ipapython import certmonger
-
-# This script a post-cert-install command for certmonger. When certmonger
-# has renewed a CA subsystem certificate a copy is put into the replicated
-# tree so it can be shared with the other IPA servers.
def main():
nickname = sys.argv[1]
@@ -57,40 +47,13 @@ def main():
# Fetch the new certificate
db = certs.CertDB(api.env.realm, nssdir=alias_dir)
cert = db.get_cert_from_db(nickname, pem=False)
-
if not cert:
syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname)
sys.exit(1)
- # Update or add it
- tmpdir = tempfile.mkdtemp(prefix = "tmp-")
- try:
- dn = DN(('cn',nickname), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
- principal = str('host/%s@%s' % (api.env.host, api.env.realm))
- ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
- conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
- conn.connect(ccache=ccache)
- try:
- entry_attrs = conn.get_entry(dn, ['usercertificate'])
- entry_attrs['usercertificate'] = cert
- conn.update_entry(entry_attrs)
- except errors.NotFound:
- entry_attrs = conn.make_entry(
- dn,
- objectclass=['top', 'pkiuser', 'nscontainer'],
- usercertificate=[cert])
- conn.add_entry(entry_attrs)
- except errors.EmptyModlist:
- pass
- conn.disconnect()
- except Exception, e:
- syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s' % e)
- finally:
- shutil.rmtree(tmpdir)
-
# Done withing stopped_service context, CA restarted here
- update_cert_config(nickname, cert)
- update_people_entry(cert)
+ cainstance.update_cert_config(nickname, cert, configured_constants)
+ cainstance.update_people_entry(cert)
if nickname == 'auditSigningCert cert-pki-ca':
# Fix trust on the audit cert
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index 7628e9b9e..7dc2c57e7 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -2,8 +2,9 @@
#
# Authors:
# Rob Crittenden <rcritten@redhat.com>
+# Jan Cholasta <jcholast@redhat.com>
#
-# Copyright (C) 2012 Red Hat
+# Copyright (C) 2013 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
@@ -20,19 +21,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
-import shutil
-import tempfile
import syslog
-import time
import traceback
+
from ipapython import services as ipaservices
-from ipapython import ipautil
-from ipaserver.install import certs
-from ipaserver.install.cainstance import update_people_entry
from ipalib import api
-from ipapython.dn import DN
-from ipalib import errors
-from ipaserver.plugins.ldap2 import ldap2
+from ipaserver.install import certs, cainstance
+
+nickname = 'ipaCert'
def main():
api.bootstrap(context='restart')
@@ -40,58 +36,22 @@ def main():
# Fetch the new certificate
db = certs.CertDB(api.env.realm)
- dercert = db.get_cert_from_db('ipaCert', pem=False)
+ dercert = db.get_cert_from_db(nickname, pem=False)
+ if not dercert:
+ syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname)
+ sys.exit(1)
# Load it into dogtag
- update_people_entry(dercert)
-
- attempts = 0
- updated = False
-
- # Store it in the IPA LDAP server
- while attempts < 10:
- conn = None
- tmpdir = None
- try:
- tmpdir = tempfile.mkdtemp(prefix="tmp-")
- dn = DN(('cn','ipaCert'), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
- principal = str('host/%s@%s' % (api.env.host, api.env.realm))
- ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
- conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
- conn.connect(ccache=ccache)
- try:
- entry_attrs = conn.get_entry(dn, ['usercertificate'])
- entry_attrs['usercertificate'] = dercert
- conn.update_entry(entry_attrs)
- except errors.NotFound:
- entry_attrs = conn.make_entry(
- dn,
- objectclass=['top', 'pkiuser', 'nscontainer'],
- usercertificate=[dercert])
- conn.add_entry(entry_attrs)
- except errors.EmptyModlist:
- pass
- updated = True
- break
- except Exception, e:
- syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s. Sleeping 30s' % e)
- time.sleep(30)
- attempts += 1
- finally:
- if conn is not None and conn.isconnected():
- conn.disconnect()
- if tmpdir is not None:
- shutil.rmtree(tmpdir)
-
- if not updated:
- syslog.syslog(syslog.LOG_ERR, '%s: Giving up. This script may be safely re-executed.' % sys.argv[0])
- sys.exit(1)
+ cainstance.update_people_entry(dercert)
# Now restart Apache so the new certificate is available
+ syslog.syslog(syslog.LOG_NOTICE, "Restarting httpd")
try:
ipaservices.knownservices.httpd.restart()
except Exception, e:
- syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e))
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % e)
+ else:
+ syslog.syslog(syslog.LOG_NOTICE, "Restarted httpd")
try:
main()
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index de5029971..cc0172f5f 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -607,10 +607,10 @@ def enable_certificate_renewal(ca):
return False
if not sysupgrade.get_upgrade_state('dogtag', 'renewal_configured'):
+ ca.configure_certmonger_renewal()
if ca.is_master():
ca.configure_renewal()
else:
- ca.configure_certmonger_renewal()
ca.configure_clone_renewal()
ca.configure_agent_renewal()
ca.track_servercert()
@@ -656,10 +656,10 @@ def certificate_renewal_stop_ca(ca):
# Ok, now we need to stop tracking, then we can start tracking them
# again with new configuration:
cainstance.stop_tracking_certificates(dogtag.configured_constants())
+ ca.configure_certmonger_renewal()
if ca.is_master():
ca.configure_renewal()
else:
- ca.configure_certmonger_renewal()
ca.configure_clone_renewal()
ca.configure_agent_renewal()
ca.track_servercert()
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 3458b312d..227cea00e 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -470,9 +470,10 @@ class CAInstance(service.Service):
self.step("requesting RA certificate from CA", self.__request_ra_certificate)
self.step("issuing RA agent certificate", self.__issue_ra_cert)
self.step("adding RA agent as a trusted user", self.__configure_ra)
+ self.step("configure certmonger for renewals", self.configure_certmonger_renewal)
+ if not self.clone:
self.step("configure certificate renewals", self.configure_renewal)
else:
- self.step("configure certmonger for renewals", self.configure_certmonger_renewal)
self.step("configure clone certificate renewals", self.configure_clone_renewal)
self.step("configure Server-Cert certificate renewal", self.track_servercert)
self.step("Configure HTTP to proxy connections", self.__http_proxy)
@@ -1428,11 +1429,6 @@ class CAInstance(service.Service):
"certmonger failed to start tracking certificate: %s" % str(e))
def configure_renewal(self):
- cmonger = ipaservices.knownservices.certmonger
- cmonger.enable()
- ipaservices.knownservices.messagebus.start()
- cmonger.start()
-
pin = self.__get_ca_pin()
# Server-Cert cert-pki-ca is renewed per-server
@@ -1441,28 +1437,41 @@ class CAInstance(service.Service):
'subsystemCert cert-pki-ca']:
try:
certmonger.dogtag_start_tracking(
- 'dogtag-ipa-renew-agent', nickname, pin, None,
- self.dogtag_constants.ALIAS_DIR, 'stop_pkicad', 'renew_ca_cert "%s"' % nickname)
+ ca='dogtag-ipa-ca-renew-agent',
+ nickname=nickname,
+ pin=pin,
+ pinfile=None,
+ secdir=self.dogtag_constants.ALIAS_DIR,
+ pre_command='stop_pkicad',
+ post_command='renew_ca_cert "%s"' % nickname)
except (ipautil.CalledProcessError, RuntimeError), e:
root_logger.error(
- "certmonger failed to start tracking certificate: %s" % str(e))
+ "certmonger failed to start tracking certificate: "
+ "%s" % e)
# Set up the agent cert for renewal
try:
- certmonger.dogtag_start_tracking('dogtag-ipa-renew-agent', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', None, 'renew_ra_cert')
+ certmonger.dogtag_start_tracking(
+ ca='dogtag-ipa-ca-renew-agent',
+ nickname='ipaCert',
+ pin=None,
+ pinfile='/etc/httpd/alias/pwdfile.txt',
+ secdir='/etc/httpd/alias',
+ pre_command=None,
+ post_command='renew_ra_cert')
except (ipautil.CalledProcessError, RuntimeError), e:
- root_logger.error(
- "certmonger failed to start tracking certificate: %s" % str(e))
+ root_logger.error(
+ "certmonger failed to start tracking certificate: %s" % e)
def configure_certmonger_renewal(self):
"""
Create a new CA type for certmonger that will retrieve updated
certificates from the dogtag master server.
"""
+ ipaservices.knownservices.messagebus.start()
cmonger = ipaservices.knownservices.certmonger
cmonger.enable()
- ipaservices.knownservices.messagebus.start()
- cmonger.restart()
+ cmonger.start()
bus = dbus.SystemBus()
obj = bus.get_object('org.fedorahosted.certmonger',
67' href='#n667'>667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
/*
 *   fs/cifs/misc.c
 *
 *   Copyright (C) International Business Machines  Corp., 2002,2008
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smberr.h"
#include "nterr.h"
#include "cifs_unicode.h"

extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;

/* The xid serves as a useful identifier for each incoming vfs request,
   in a similar way to the mid which is useful to track each sent smb,
   and CurrentXid can also provide a running counter (although it
   will eventually wrap past zero) of the total vfs operations handled
   since the cifs fs was mounted */

unsigned int
_GetXid(void)
{
	unsigned int xid;

	spin_lock(&GlobalMid_Lock);
	GlobalTotalActiveXid++;

	/* keep high water mark for number of simultaneous ops in filesystem */
	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
		GlobalMaxActiveXid = GlobalTotalActiveXid;
	if (GlobalTotalActiveXid > 65000)
		cFYI(1, ("warning: more than 65000 requests active"));
	xid = GlobalCurrentXid++;
	spin_unlock(&GlobalMid_Lock);
	return xid;
}

void
_FreeXid(unsigned int xid)
{
	spin_lock(&GlobalMid_Lock);
	/* if (GlobalTotalActiveXid == 0)
		BUG(); */
	GlobalTotalActiveXid--;
	spin_unlock(&GlobalMid_Lock);
}

struct cifsSesInfo *
sesInfoAlloc(void)
{
	struct cifsSesInfo *ret_buf;

	ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
	if (ret_buf) {
		atomic_inc(&sesInfoAllocCount);
		ret_buf->status = CifsNew;
		++ret_buf->ses_count;
		INIT_LIST_HEAD(&ret_buf->smb_ses_list);
		INIT_LIST_HEAD(&ret_buf->tcon_list);
		init_MUTEX(&ret_buf->sesSem);
	}
	return ret_buf;
}

void
sesInfoFree(struct cifsSesInfo *buf_to_free)
{
	if (buf_to_free == NULL) {
		cFYI(1, ("Null buffer passed to sesInfoFree"));
		return;
	}

	atomic_dec(&sesInfoAllocCount);
	kfree(buf_to_free->serverOS);
	kfree(buf_to_free->serverDomain);
	kfree(buf_to_free->serverNOS);
	if (buf_to_free->password) {
		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
		kfree(buf_to_free->password);
	}
	kfree(buf_to_free->domainName);
	kfree(buf_to_free);
}

struct cifsTconInfo *
tconInfoAlloc(void)
{
	struct cifsTconInfo *ret_buf;
	ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
	if (ret_buf) {
		atomic_inc(&tconInfoAllocCount);
		ret_buf->tidStatus = CifsNew;
		++ret_buf->tc_count;
		INIT_LIST_HEAD(&ret_buf->openFileList);
		INIT_LIST_HEAD(&ret_buf->tcon_list);
#ifdef CONFIG_CIFS_STATS
		spin_lock_init(&ret_buf->stat_lock);
#endif
	}
	return ret_buf;
}

void
tconInfoFree(struct cifsTconInfo *buf_to_free)
{
	if (buf_to_free == NULL) {
		cFYI(1, ("Null buffer passed to tconInfoFree"));
		return;
	}
	atomic_dec(&tconInfoAllocCount);
	kfree(buf_to_free->nativeFileSystem);
	if (buf_to_free->password) {
		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
		kfree(buf_to_free->password);
	}
	kfree(buf_to_free);
}

struct smb_hdr *
cifs_buf_get(void)
{
	struct smb_hdr *ret_buf = NULL;

/* We could use negotiated size instead of max_msgsize -
   but it may be more efficient to always alloc same size
   albeit slightly larger than necessary and maxbuffersize
   defaults to this and can not be bigger */
	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);

	/* clear the first few header bytes */
	/* for most paths, more is cleared in header_assemble */
	if (ret_buf) {
		memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);
		atomic_inc(&bufAllocCount);
#ifdef CONFIG_CIFS_STATS2
		atomic_inc(&totBufAllocCount);
#endif /* CONFIG_CIFS_STATS2 */
	}

	return ret_buf;
}

void
cifs_buf_release(void *buf_to_free)
{
	if (buf_to_free == NULL) {
		/* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
		return;
	}
	mempool_free(buf_to_free, cifs_req_poolp);

	atomic_dec(&bufAllocCount);
	return;
}

struct smb_hdr *
cifs_small_buf_get(void)
{
	struct smb_hdr *ret_buf = NULL;

/* We could use negotiated size instead of max_msgsize -
   but it may be more efficient to always alloc same size
   albeit slightly larger than necessary and maxbuffersize
   defaults to this and can not be bigger */
	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
	if (ret_buf) {
	/* No need to clear memory here, cleared in header assemble */
	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
		atomic_inc(&smBufAllocCount);
#ifdef CONFIG_CIFS_STATS2
		atomic_inc(&totSmBufAllocCount);
#endif /* CONFIG_CIFS_STATS2 */

	}
	return ret_buf;
}

void
cifs_small_buf_release(void *buf_to_free)
{

	if (buf_to_free == NULL) {
		cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
		return;
	}
	mempool_free(buf_to_free, cifs_sm_req_poolp);

	atomic_dec(&smBufAllocCount);
	return;
}

/*
	Find a free multiplex id (SMB mid). Otherwise there could be
	mid collisions which might cause problems, demultiplexing the
	wrong response to this request. Multiplex ids could collide if
	one of a series requests takes much longer than the others, or
	if a very large number of long lived requests (byte range
	locks or FindNotify requests) are pending.  No more than
	64K-1 requests can be outstanding at one time.  If no
	mids are available, return zero.  A future optimization
	could make the combination of mids and uid the key we use
	to demultiplex on (rather than mid alone).
	In addition to the above check, the cifs demultiplex
	code already used the command code as a secondary
	check of the frame and if signing is negotiated the
	response would be discarded if the mid were the same
	but the signature was wrong.  Since the mid is not put in the
	pending queue until later (when it is about to be dispatched)
	we do have to limit the number of outstanding requests
	to somewhat less than 64K-1 although it is hard to imagine
	so many threads being in the vfs at one time.
*/
__u16 GetNextMid(struct TCP_Server_Info *server)
{
	__u16 mid = 0;
	__u16 last_mid;
	int   collision;

	if (server == NULL)
		return mid;

	spin_lock(&GlobalMid_Lock);
	last_mid = server->CurrentMid; /* we do not want to loop forever */
	server->CurrentMid++;
	/* This nested loop looks more expensive than it is.
	In practice the list of pending requests is short,
	fewer than 50, and the mids are likely to be unique
	on the first pass through the loop unless some request
	takes longer than the 64 thousand requests before it
	(and it would also have to have been a request that
	 did not time out) */
	while (server->CurrentMid != last_mid) {
		struct list_head *tmp;
		struct mid_q_entry *mid_entry;

		collision = 0;
		if (server->CurrentMid == 0)
			server->CurrentMid++;

		list_for_each(tmp, &server->pending_mid_q) {
			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);

			if ((mid_entry->mid == server->CurrentMid) &&
			    (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
				/* This mid is in use, try a different one */
				collision = 1;
				break;
			}
		}
		if (collision == 0) {
			mid = server->CurrentMid;
			break;
		}
		server->CurrentMid++;
	}
	spin_unlock(&GlobalMid_Lock);
	return mid;
}

/* NB: MID can not be set if treeCon not passed in, in that
   case it is responsbility of caller to set the mid */
void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
		const struct cifsTconInfo *treeCon, int word_count
		/* length of fixed section (word count) in two byte units  */)
{
	struct list_head *temp_item;
	struct cifsSesInfo *ses;
	char *temp = (char *) buffer;

	memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */

	buffer->smb_buf_length =
	    (2 * word_count) + sizeof(struct smb_hdr) -
	    4 /*  RFC 1001 length field does not count */  +
	    2 /* for bcc field itself */ ;
	/* Note that this is the only network field that has to be converted
	   to big endian and it is done just before we send it */

	buffer->Protocol[0] = 0xFF;
	buffer->Protocol[1] = 'S';
	buffer->Protocol[2] = 'M';
	buffer->Protocol[3] = 'B';
	buffer->Command = smb_command;
	buffer->Flags = 0x00;	/* case sensitive */
	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
	buffer->Pid = cpu_to_le16((__u16)current->tgid);
	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
	if (treeCon) {
		buffer->Tid = treeCon->tid;
		if (treeCon->ses) {
			if (treeCon->ses->capabilities & CAP_UNICODE)
				buffer->Flags2 |= SMBFLG2_UNICODE;
			if (treeCon->ses->capabilities & CAP_STATUS32)
				buffer->Flags2 |= SMBFLG2_ERR_STATUS;

			/* Uid is not converted */
			buffer->Uid = treeCon->ses->Suid;
			buffer->Mid = GetNextMid(treeCon->ses->server);
			if (multiuser_mount != 0) {
		/* For the multiuser case, there are few obvious technically  */
		/* possible mechanisms to match the local linux user (uid)    */
		/* to a valid remote smb user (smb_uid):		      */
		/* 	1) Query Winbind (or other local pam/nss daemon       */
		/* 	  for userid/password/logon_domain or credential      */
		/*      2) Query Winbind for uid to sid to username mapping   */
		/* 	   and see if we have a matching password for existing*/
		/*         session for that user perhas getting password by   */
		/*         adding a new pam_cifs module that stores passwords */
		/*         so that the cifs vfs can get at that for all logged*/
		/*	   on users					      */
		/*	3) (Which is the mechanism we have chosen)	      */
		/*	   Search through sessions to the same server for a   */
		/*	   a match on the uid that was passed in on mount     */
		/*         with the current processes uid (or euid?) and use  */
		/* 	   that smb uid.   If no existing smb session for     */
		/* 	   that uid found, use the default smb session ie     */
		/*         the smb session for the volume mounted which is    */
		/* 	   the same as would be used if the multiuser mount   */
		/* 	   flag were disabled.  */

		/*  BB Add support for establishing new tCon and SMB Session  */
		/*      with userid/password pairs found on the smb session   */
		/*	for other target tcp/ip addresses 		BB    */
				if (current_fsuid() != treeCon->ses->linux_uid) {
					cFYI(1, ("Multiuser mode and UID "
						 "did not match tcon uid"));
					read_lock(&cifs_tcp_ses_lock);
					list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
						ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
						if (ses->linux_uid == current_fsuid()) {
							if (ses->server == treeCon->ses->server) {
								cFYI(1, ("found matching uid substitute right smb_uid"));
								buffer->Uid = ses->Suid;
								break;
							} else {
				/* BB eventually call cifs_setup_session here */
								cFYI(1, ("local UID found but no smb sess with this server exists"));
							}
						}
					}
					read_unlock(&cifs_tcp_ses_lock);
				}
			}
		}
		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
			buffer->Flags2 |= SMBFLG2_DFS;
		if (treeCon->nocase)
			buffer->Flags  |= SMBFLG_CASELESS;
		if ((treeCon->ses) && (treeCon->ses->server))
			if (treeCon->ses->server->secMode &
			  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
	}

/*  endian conversion of flags is now done just before sending */
	buffer->WordCount = (char) word_count;
	return;
}

static int
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{
	/* Make sure that this really is an SMB, that it is a response,
	   and that the message ids match */
	if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
		(mid == smb->Mid)) {
		if (smb->Flags & SMBFLG_RESPONSE)
			return 0;
		else {
		/* only one valid case where server sends us request */
			if (smb->Command == SMB_COM_LOCKING_ANDX)
				return 0;
			else
				cERROR(1, ("Received Request not response"));
		}
	} else { /* bad signature or mid */
		if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
			cERROR(1,
			       ("Bad protocol string signature header %x",
				*(unsigned int *) smb->Protocol));
		if (mid != smb->Mid)
			cERROR(1, ("Mids do not match"));
	}
	cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid));
	return 1;
}

int
checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
{
	__u32 len = smb->smb_buf_length;
	__u32 clc_len;  /* calculated length */
	cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));

	if (length < 2 + sizeof(struct smb_hdr)) {
		if ((length >= sizeof(struct smb_hdr) - 1)
			    && (smb->Status.CifsError != 0)) {
			smb->WordCount = 0;
			/* some error cases do not return wct and bcc */
			return 0;
		} else if ((length == sizeof(struct smb_hdr) + 1) &&
				(smb->WordCount == 0)) {
			char *tmp = (char *)smb;
			/* Need to work around a bug in two servers here */
			/* First, check if the part of bcc they sent was zero */
			if (tmp[sizeof(struct smb_hdr)] == 0) {
				/* some servers return only half of bcc
				 * on simple responses (wct, bcc both zero)
				 * in particular have seen this on
				 * ulogoffX and FindClose. This leaves
				 * one byte of bcc potentially unitialized
				 */
				/* zero rest of bcc */
				tmp[sizeof(struct smb_hdr)+1] = 0;
				return 0;
			}
			cERROR(1, ("rcvd invalid byte count (bcc)"));
		} else {
			cERROR(1, ("Length less than smb header size"));
		}
		return 1;
	}
	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
		cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
				   smb->Mid));
		return 1;
	}

	if (checkSMBhdr(smb, mid))
		return 1;
	clc_len = smbCalcSize_LE(smb);

	if (4 + len != length) {
		cERROR(1, ("Length read does not match RFC1001 length %d",
			   len));
		return 1;
	}

	if (4 + len != clc_len) {
		/* check if bcc wrapped around for large read responses */
		if ((len > 64 * 1024) && (len > clc_len)) {
			/* check if lengths match mod 64K */
			if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
				return 0; /* bcc wrapped */
		}
		cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
				clc_len, 4 + len, smb->Mid));
		/* Windows XP can return a few bytes too much, presumably
		an illegal pad, at the end of byte range lock responses
		so we allow for that three byte pad, as long as actual
		received length is as long or longer than calculated length */
		/* We have now had to extend this more, since there is a
		case in which it needs to be bigger still to handle a
		malformed response to transact2 findfirst from WinXP when
		access denied is returned and thus bcc and wct are zero
		but server says length is 0x21 bytes too long as if the server
		forget to reset the smb rfc1001 length when it reset the
		wct and bcc to minimum size and drop the t2 parms and data */
		if ((4+len > clc_len) && (len <= clc_len + 512))
			return 0;
		else {
			cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
					len, smb->Mid));
			return 1;
		}
	}
	return 0;
}

bool
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
{
	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
	struct list_head *tmp, *tmp1, *tmp2;
	struct cifsSesInfo *ses;
	struct cifsTconInfo *tcon;
	struct cifsInodeInfo *pCifsInode;
	struct cifsFileInfo *netfile;
	int rc;

	cFYI(1, ("Checking for oplock break or dnotify response"));
	if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
	   (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
		struct smb_com_transaction_change_notify_rsp *pSMBr =
			(struct smb_com_transaction_change_notify_rsp *)buf;
		struct file_notify_information *pnotify;
		__u32 data_offset = 0;
		if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
			data_offset = le32_to_cpu(pSMBr->DataOffset);

			pnotify = (struct file_notify_information *)
				((char *)&pSMBr->hdr.Protocol + data_offset);
			cFYI(1, ("dnotify on %s Action: 0x%x",
				 pnotify->FileName, pnotify->Action));
			/*   cifs_dump_mem("Rcvd notify Data: ",buf,
				sizeof(struct smb_hdr)+60); */
			return true;
		}
		if (pSMBr->hdr.Status.CifsError) {
			cFYI(1, ("notify err 0x%d",
				pSMBr->hdr.Status.CifsError));
			return true;
		}
		return false;
	}
	if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
		return false;
	if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
		/* no sense logging error on invalid handle on oplock
		   break - harmless race between close request and oplock
		   break response is expected from time to time writing out
		   large dirty files cached on the client */
		if ((NT_STATUS_INVALID_HANDLE) ==
		   le32_to_cpu(pSMB->hdr.Status.CifsError)) {
			cFYI(1, ("invalid handle on oplock break"));
			return true;
		} else if (ERRbadfid ==
		   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
			return true;
		} else {
			return false; /* on valid oplock brk we get "request" */
		}
	}
	if (pSMB->hdr.WordCount != 8)
		return false;

	cFYI(1, ("oplock type 0x%d level 0x%d",
		 pSMB->LockType, pSMB->OplockLevel));
	if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
		return false;

	/* look up tcon based on tid & uid */
	read_lock(&cifs_tcp_ses_lock);
	list_for_each(tmp, &srv->smb_ses_list) {
		ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
		list_for_each(tmp1, &ses->tcon_list) {
			tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
			if (tcon->tid != buf->Tid)
				continue;

			cifs_stats_inc(&tcon->num_oplock_brks);
			read_lock(&GlobalSMBSeslock);
			list_for_each(tmp2, &tcon->openFileList) {
				netfile = list_entry(tmp2, struct cifsFileInfo,
						     tlist);
				if (pSMB->Fid != netfile->netfid)
					continue;

				/*
				 * don't do anything if file is about to be
				 * closed anyway.
				 */
				if (netfile->closePend) {
					read_unlock(&GlobalSMBSeslock);
					read_unlock(&cifs_tcp_ses_lock);
					return true;
				}

				cFYI(1, ("file id match, oplock break"));
				pCifsInode = CIFS_I(netfile->pInode);
				pCifsInode->clientCanCacheAll = false;
				if (pSMB->OplockLevel == 0)
					pCifsInode->clientCanCacheRead = false;
				rc = slow_work_enqueue(&netfile->oplock_break);
				if (rc) {
					cERROR(1, ("failed to enqueue oplock "
						   "break: %d\n", rc));
				} else {
					netfile->oplock_break_cancelled = false;
				}
				read_unlock(&GlobalSMBSeslock);
				read_unlock(&cifs_tcp_ses_lock);
				return true;
			}
			read_unlock(&GlobalSMBSeslock);
			read_unlock(&cifs_tcp_ses_lock);
			cFYI(1, ("No matching file for oplock break"));
			return true;
		}
	}
	read_unlock(&cifs_tcp_ses_lock);
	cFYI(1, ("Can not process oplock break for non-existent connection"));
	return true;
}

void
dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
{
	int i, j;
	char debug_line[17];
	unsigned char *buffer;

	if (traceSMB == 0)
		return;

	buffer = (unsigned char *) smb_buf;
	for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
		if (i % 8 == 0) {
			/* have reached the beginning of line */
			printk(KERN_DEBUG "| ");
			j = 0;
		}
		printk("%0#4x ", buffer[i]);
		debug_line[2 * j] = ' ';
		if (isprint(buffer[i]))
			debug_line[1 + (2 * j)] = buffer[i];
		else
			debug_line[1 + (2 * j)] = '_';

		if (i % 8 == 7) {
			/* reached end of line, time to print ascii */
			debug_line[16] = 0;
			printk(" | %s\n", debug_line);
		}
	}
	for (; j < 8; j++) {
		printk("     ");
		debug_line[2 * j] = ' ';
		debug_line[1 + (2 * j)] = ' ';
	}
	printk(" | %s\n", debug_line);
	return;
}

/* Convert 16 bit Unicode pathname to wire format from string in current code
   page.  Conversion may involve remapping up the seven characters that are
   only legal in POSIX-like OS (if they are present in the string). Path
   names are little endian 16 bit Unicode on the wire */
int
cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
		 const struct nls_table *cp, int mapChars)
{
	int i, j, charlen;
	int len_remaining = maxlen;
	char src_char;
	__u16 temp;

	if (!mapChars)
		return cifs_strtoUCS(target, source, PATH_MAX, cp);

	for (i = 0, j = 0; i < maxlen; j++) {
		src_char = source[i];
		switch (src_char) {
			case 0:
				target[j] = 0;
				goto ctoUCS_out;
			case ':':
				target[j] = cpu_to_le16(UNI_COLON);
				break;
			case '*':
				target[j] = cpu_to_le16(UNI_ASTERIK);
				break;
			case '?':
				target[j] = cpu_to_le16(UNI_QUESTION);
				break;
			case '<':
				target[j] = cpu_to_le16(UNI_LESSTHAN);
				break;
			case '>':
				target[j] = cpu_to_le16(UNI_GRTRTHAN);
				break;
			case '|':
				target[j] = cpu_to_le16(UNI_PIPE);
				break;