Identifying a User and a Machine [duplicate] - sql

My work company has a MSSQL server 2005. I have two questions about finding out current log user and any way to send out a warning message:
First question is if there is any T-SQL or SP available to find out current login user name and machine name. If the user is using SQL server sa name to remotely access to SQL server, is there any way to find out that user's windows name (the name to log to the windows)?
My next question is that if I can get the user name or id, is there any way to send out a warning message such as "currently SQL server is clean up or backup, please do not log in at this time". I guess it may be difficult. I may have to send an email out to the user.
The SQL server is only accessible in the company. The SQL server has a list of users as login users: windows users, SQL users and sa.

SELECT SUSER_SNAME(), HOST_NAME()
If the connection is "sa" (or any other SQL login) then you can't find the domain/windows user name. SQL Server only knows it's "sa" or that SQL login.
HOST_NAME may not be reliable either, it can be set in the connection string ("Application Name"). Or it could be vague eg "Microsoft Office" for by default for Access, Excel etc
You could backtrack via client_net_address in sys.dm_exec_connections and match MAC address to IP and find out who is logged on...

An easy way to find out both host and user is
EXEC sp_who2;
where you get some other information that can be good to know, as if the user is active and so on...
It does not resolve the issues that gbn announced.

Thanks for all your suggestions first. I tried all the methods and I think Joakim Backman's method meet my need. Here is summary of what I find out.
Query of sys.syslogins only list login information. The accdate does not give the current login user timestamp. I tried to login from another application to my SQL and this query does not list the login.
SELECT SUSER_SNAME(), HOST_NAME() only list one user on SQL server. For example, I log in in as my name to SQL server. The result of this query only lists my name and machine name. This query does not list current users on the SQL server.
exec sp_who2 lists information I need. It lists current user name machine name, active status, db name user's access, and command used.
In order to get the information I use in SP, I have to filter and join the information with other tables, such as emails. Here is the codes I use:
DECLARE #retTable TABLE (
SPID int not null
, Status varchar (255) not null
, Login varchar (255) not null
, HostName varchar (255) not null
, BlkBy varchar(10) not null
, DBName varchar (255) null
, Command varchar (255) not null
, CPUTime int not null
, DiskIO int not null
, LastBatch varchar (255) not null
, ProgramName varchar (255) null
, SPID2 int not null
, REQUESTID INT
)
INSERT INTO #retTable EXEC sp_who2
SELECT Status, Login, HostName, DBName, Command, CPUTime, ProgramName -- *
FROM #retTable
--WHERE Login not like 'sa%' -- if not interested in sa
ORDER BY Login, HostName

Related

List the User mapped to a Login on one particular database

I'm back here with a SQL User/Login problem.
First off all i'm working on SQL server 2008 and i'm not the master on that server.
On that SQL server i have different Login and these Login are mapped to a USER to my database 'DB_MyDataBase'.
Indeed, i have 10 different Login mapped to 10 different User on my database 'DB_MyDataBase'.
For i.e., when i'm connecting to the SQL server with a Login 'Laurent', That SQL Login 'Laurent' is the USER 'Laurel' on my database 'DB_MyDataBase'. For the moment, no problem.
But now for that 10 different Login and want to know their respective USER for my database 'DB_MyDataBase'.
After some research i've found a request that can do "the job"
sp_msloginmappings 'Laurent', 1
Normally, that show mapping user account info in current databases context for login account 'Laurent'
But when i tried it, i had a error message.
Nom d'objet 'dbo.syslogins' non valide.
Error message is : Object name 'dbo.syslogins' is not valid for non French users.
I've found another request which is working "a bit".
SET NOCOUNT ON
CREATE TABLE #temp
(
SERVER_name SYSNAME NULL ,
Database_name SYSNAME NULL ,
UserName SYSNAME ,
GroupName SYSNAME ,
LoginName SYSNAME NULL ,
DefDBName SYSNAME NULL ,
DefSchemaName SYSNAME NULL ,
UserID INT ,
[SID] VARBINARY(85)
)
DECLARE #command VARCHAR(MAX)
--this will contain all the databases (and their sizes!)
--on a server
DECLARE #databases TABLE
(
Database_name VARCHAR(128) ,
Database_size INT ,
remarks VARCHAR(255)
)
INSERT INTO #databases--stock the table with the list of databases
EXEC sp_databases
SELECT #command = COALESCE(#command, '') + '
USE ' + database_name + '
insert into #temp (UserName,GroupName, LoginName,
DefDBName, DefSchemaName,UserID,[SID])
Execute sp_helpuser
UPDATE #TEMP SET database_name=DB_NAME(),
server_name=##ServerName
where database_name is null
'
FROM #databases
EXECUTE ( #command )
SELECT loginname ,
UserName ,
Database_name
FROM #temp
WHERE LoginName = 'Laurent'
So that one is working it's listing all User mapped to that Login on every database BUT (there is always a "but"...) it's only working with the Login i use to connect.
For i.e. When i connect to the SQL server with Login 'Laurent' the previous request is working because i request for the same Login that i used to connect to the SQL server but when i connect with Login 'Laurent' and do the previous request with a different Login (so not 'Laurent' but another one which have a user mapped to my database 'DB_MyDataBase'.) I don't see anything, it returns me blank column....
Maybe it's because i'm not master on that SQL server.
So how i can list User mapped to a Login different from the one i'm connected?
I hope my question is clear enough (sorry for long text) and thanks for your future answer. Don't hesitate to ask me if you need further info to answer me.
What you can see will depend on the permissions of the user you are logged in as. This query against two of the security catalog views should give you what you want provided you have the necessary permission.
select
dp.name as UserName,
sp.name as LoginName
from
sys.database_principals dp
left join sys.server_principals sp on sp.sid = dp.sid
where
dp.type in ('S', 'U')

How to find the number of concurrent SQL Server connections

I have a SQL Server that is reaching the max limit of concurrent connections. I have many different servers & services connecting to one SQL Server at the same time.
I did find another query that seems to work:
SELECT DB_NAME(dbid) AS DBName,
COUNT(dbid) AS NumberOfConnections,
loginame AS LoginName,
nt_domain AS NT_Domain,
nt_username AS NT_UserName,
hostname AS HostName
FROM sys.sysprocesses
WHERE dbid > 0
GROUP BY dbid,
hostname,
loginame,
nt_domain,
nt_username
ORDER BY NumberOfConnections DESC;
However, this gives me the number of connections which is good. How do i further dig down this to find to see the each connection and what action they are doing?
the sql command "sp_who" which provides information about current users, sessions, and processes in an instance of the Microsoft SQL Server Database Engine (MSDN) From here, you should be able to send the results into a temp table and group them by servername.
such as the following...
CREATE TABLE #tbl (
spid int
, ecid int
, status varchar(50)
, loginame varchar(255)
, hostname varchar(255)
, blk varchar(50)
, dbname varchar(255)
, cmd varchar(255)
, request_id varchar(255)
)
GO
INSERT INTO #tbl EXEC sp_who
SELECT COUNT(0), hostname FROM #tbl group by hostname
DROP TABLE #tbl
GO
Are you talking about how to check the connections that are reaching your SQL Server instance? How about some DOS commands? try to search for the port 1433 or for the PID of your SQL Server process.
netstat -nao | find "1433"
To find the PID (process identifier) that you are looking for, just go to your task manager and customize the processes view, mode details here:
http://www.mydigitallife.info/how-to-get-and-view-process-identifier-process-id-or-pid-on-windows/

T-SQL: SUSER_SNAME vs SUSER_NAME?

The MSDN documentation says for SUSER_SNAME function:
Returns the login identification name from a user's security identification number (SID).
More over, it says for the SUSER_NAME function:
Returns the login identification name of the user.
Nonetheless, when I execute the following SQL statements I get the same result:
SELECT SUSER_NAME();
SELECT SUSER_SNAME();
So, what are differences, and which one shall I use? Is there a situation I should use one rather that the other?
Please advice,
Thanks in advance :)
If you call the function without an argument they will both return the same value. But they do take different arguments:
SUSER_SNAME() takes the varbinary(85) SID of a login as argument
SUSER_NAME() takes the integer principal_id of a login
You can verify this like:
select suser_name(principal_id)
, suser_name(sid)
, suser_sname(principal_id)
, suser_sname(sid)
from sys.server_principals
where name = suser_name()
Only the first and last column will return non-null values.
SUSER_NAME() will return the name associated with an sid that exists in sys.server_principals. The sid must exist in sys.server_principals.
SUSER_SNAME() can do that but also can return the sid of a login if the login is a member of an active directory group
So if you have [CONTOSO\MyGroup] in Active Directory and that group has one user [CONTOSO\MyUser]
And you add that group to SQL Server:
CREATE LOGIN [CONTOSO\MyGroup] FROM WINDOWS;
SELECT SUSER_ID('CONTOSO\MyUser'), SUSER_SID('CONTOSO\MyUser')
will give you
NULL, CONTOSO\MyUser
because CONTOSO\MyUser is not in sys.server_principals but is in A/D

Error : Cannot fetch a row from OLE DB provider "ADsDSOObject" for linked server "ADSI"

When I attempt to query AD for users I receive the following error:
Cannot fetch a row from OLE DB provider "ADsDSOObject" for linked server "ADSI".
I assume the issue due to the 1000 row limit (or 901 rows in SqlServer 2008). I can page the query but I am looking for workaround that would allow me to retrieve more than 1000 at a time.
In case it helps, I am using SqlServer 2008 R2.
and here is my query
SELECT samaccountname AS Account, ISNULL(givenName, '''') AS givenName, ISNULL(SN, '''') AS SN, ISNULL(DisplayName, '''') as DisplayName, ISNULL(Title, '''') AS Title
FROM OpenQuery(ADSI,
'SELECT SamAccountName, givenName, SN, DisplayName, Title
FROM ''LDAP://corpdomain.corp''
WHERE objectClass = ''User'' and (SN = ''*'' or givenName = ''*'')')
Any ideas?
EDIT -
Upon further inspection I realized I am not able to properly page this query either. Does anyone have any tips on a solution that will allow me to page the results or a workaround that will allow me to return more than 901?
I hit this problem too, and didn't like the usual solution posted of paging by the first letter of the account name. This would mean 26 separate calls to AD, and also could still potentially fail because with a large domain its very possible to have more than 901 accounts starting with the same first letter - particularly if you are looking at computer accounts, which likely follow some systematic naming convention using the same first letter...
I did some playing around and I found that if you order the openquery by uSNCreated and put a TOP 901 clause on the outer query it doesn't blow up.
So, here is my SQL which fetches ALL active directory objects (computers, domain controllers, users and contacts) into a temp table in chunks of 901 records and gives you some useful information on each object.
CREATE TABLE #ADData(
Login NVARCHAR(256)
,CommonName NVARCHAR(256)
,GivenName NVARCHAR(256)
,FamilyName NVARCHAR(256)
,DisplayName NVARCHAR(256)
,Title NVARCHAR(256)
,Department NVARCHAR(256)
,Location NVARCHAR(256)
,Info NVARCHAR(256)
,LastLogin BIGINT
,flags INT
,Email NVARCHAR(256)
,Phone NVARCHAR(256)
,Mobile NVARCHAR(256)
,Quickdial NVARCHAR(256)
, usnCreated INT
)
DECLARE #Query VARCHAR (2000)
DECLARE #Filter VARCHAR(200)
DECLARE #Rowcount INT
select #Filter =''
WHILE ISNULL(#rowcount,901) = 901 BEGIN
SELECT #Query = '
SELECT top 901
Login = SamAccountName
, CommonName = cn
, GivenName
, FamilyName = sn
, DisplayName
, Title
, Department
, Location = physicalDeliveryOfficeName
, Info
, LastLogin = CAST(LastLogon AS bigint)
, flags = CAST (UserAccountControl as int)
, Email = mail
, Phone = telephoneNumber
, Mobile = mobile
, QuickDial = Pager
, usnCreated
FROM OPENROWSET(''ADSDSOObject'', '''', ''
SELECT cn, givenName, sn, userAccountControl, lastLogon, displayName, samaccountname,
title, department, physicalDeliveryOfficeName, info, mail, telephoneNumber, mobile, pager, usncreated
FROM ''''LDAP://[ldap-query-string]''''
WHERE objectClass=''''Person''''
AND objectClass = ''''User''''
' + #filter + '
ORDER BY usnCreated'')'
INSERT INTO #ADData EXEC (#Query)
SELECT #Rowcount = ##ROWCOUNT
SELECT #Filter = 'and usnCreated > '+ LTRIM(STR((SELECT MAX(usnCreated) FROM #ADData)))
END
SELECT LOGIN
, CommonName
, GivenName
, FamilyName
, DisplayName
, Title
, Department
, Location
, Email
, Phone
, QuickDial
, Mobile
, Info
, Disabled = CASE WHEN CAST (flags AS INT) & 2 > 0 THEN 'Y' ELSE NULL END
, Locked = CASE WHEN CAST (flags AS INT) & 16 > 0 THEN 'Y' ELSE NULL END
, NoPwdExpiry = CASE WHEN CAST (flags AS INT) & 65536 > 0 THEN 'Y' ELSE NULL END
, LastLogin = CASE WHEN ISNULL(CAST (LastLogin AS BIGINT),0) = 0 THEN NULL ELSE
DATEADD(ms, (CAST (LastLogin AS BIGINT) / CAST(10000 AS BIGINT)) % 86400000,
DATEADD(day, CAST (LastLogin AS BIGINT) / CAST(864000000000 AS BIGINT) - 109207, 0)) END
, Type = CASE WHEN flags & 512 = 512 THEN 'user'
WHEN flags IS NULL THEN 'contact'
WHEN flags & 4096 = 4096 THEN 'computer'
WHEN flags & 532480 = 532480 THEN 'computer (DC)' END
FROM #ADData
ORDER BY Login
DROP TABLE #ADData
The problem
When I attempt to query AD for users I receive the following error:
Cannot fetch a row from OLE DB provider "ADsDSOObject" for linked server "ADSI".
I assume the issue due to the 1000 row limit (or 901 rows in SqlServer 2008). I can page the query >but I am looking for workaround that would allow me to retrieve more than 1000 at a time.
In case it helps, I am using SqlServer 2008 R2. and here is my query
>
SELECT samaccountname AS Account, ISNULL(givenName, '''') AS givenName, ISNULL(SN, '''') AS SN, ISNULL(DisplayName, '''') as DisplayName, ISNULL(Title, '''') AS Title
FROM OpenQuery(ADSI,
'SELECT SamAccountName, givenName, SN, DisplayName, Title
FROM ''LDAP://corpdomain.corp''
WHERE objectClass = ''User'' and (SN = ''*'' or givenName = ''*''
Any ideas?
EDIT - Upon further inspection I realized I am not able to properly page this query either. Does >anyone have any tips on a solution that will allow me to page the results or a workaround that will >allow me to return more than 901?
My workaround
I just solved the same problem faced by me, by applying paging optimally (and I am successfully able to retrieve around 50k logins from the AD and it is not missing to fetch a single login account from the AD domains):
You need to work around the ADSI query limitation by looping through the characters of the attributes. See a solution here: http://www.sqlservercentral.com/Forums/Topic231658-54-1.aspx#bm1249991
The error was resolved by writing SELECT TOP 901 ... IN PLACE OF JUST SELECT.
And yes, this problem is related to using SqlServer 2008 R2. This problem occurred to me after migration of the database from 2005 to 2008, because in SQL Server 2008, there is a limit of 901 rows which was 1000 in SQL Server 2005 (the difference is we need to write select TOP 901, which was not required in the SQL Server 2005, else the program fails with error)
From your reply to my comment it sound like an SSIS package fired by a SQL Agent job would be an ideal way to go. Here's how you can access Active Directory in SSIS:
Create a new SSIS Project
Add a Data Flow Task to the Control Flow.
Click the Data Flow tab.
Drag an ADO NET Source from the Toolbox to the Data Flow.
Double-click the ADO NET Source.
Click the New button next to OLE DB connection manager.
Click the New button in the Configure ADO.NET Connection Manager
dialog.
Click the downward pointing arrow on the Provider dropdown.
Find .Net Providers for OleDb in the list and double-click it.
Find OLE DB Provider for Microsoft Directory Services in the list
and double-click it.
Click the OK button.
In Server or file name put ActiveDirectory.
Highlight ActiveDirectory in the Data connections.
Click the OK button.
Change the Data access mode to SQL command.
In the SQL command text box enter
<LDAP://DC=domain,DC=tld>;(&(objectClass=User)(objectCategory=Person));distinguishedName,displayName,sn,givenName,middleName,mail,telephoneNumber;subtree.
Change domain and tld to the appropriate identifiers for your
domain and add any other appropriate LDAP path elements.
Add any other appropriate ActiveDirectory attributes to the query.
Click the OK button.
You will see error messages indicating that the data type
"System.Object" is not supported. These can be ignored.
Click the OK button on the warning dialog.
Right-click on the ADO NET Source.
Click Properties.
Change ValidateExternalMetadata to False.
You may also want to do the steps below, but be aware that if you do this and have an Active Directory attribute longer than 4000 characters, it will be truncated in the data flow.
Right-click on the ADO NET Source.
Click Show Advanced Editor.
Go to the Input and Output Properties tab.
Expand ADO NET Source Output.
Expand Output Columns.
For each column, change the DataType to Unicode string [DT_WSTR] and
set the Length to 4000.
Click the OK button.
Double-click the ADO NET Source go to Error Output.
Select all the values for the rows under Trunctation.
List item
Under Set this value to selected cells choose Ignore failure.
Click the Apply button.
Click the OK button.
Note that this query format is also supported:
SELECT distinguishedName, displayName, sn, givenName, middleName, mail, telephoneNumber
FROM 'LDAP://DC=domain,DC=tld'
WHERE objectClass = 'User' AND objectCategory = 'Person'
See the MSDN article Microsoft OLE DB Provider for Microsoft Active Directory Service for more information on the query formats supported by the provider.
This exact same Cannot fetch a row from OLE DB provider "ADSDSOObject" error message can also occur when you have less than 1000 rows in the resultset, but something else prevents SQL from fetching the records. We recently had a situation where the SQL Service account password was out of date, and this seems to have caused this error. Updating the password in the Log on details of the service and restarting SQL Server fixed it.
Just thought I would tack this answer on here so if someone googles this error message in future this might also help!
I solved it using another post by Magnus Reuter -just thought I gave y'all a link because it is simple ans ingenious!
He did 2 queries, joining them by using UNION, but for the first one he selected all sAMAccountname m. Of course if you find that your middle is not the letter "m" you can adjust that accordingly, but generally if you have around 1000-2000 records it will be "m".
Retrieve >901 rows from SQL Server 2008 linked server to Active Directory
There is an additional reason why you might get this error. If you are using multiple domains you may need to change the Active Directory properties for this SQL Server. Selecting "Trust this computer for delegation to any service (Kerberos only)" should correct the problem if the cause is from "double hop" in a multi-domain setup.

How to find out user name and machine name to access to SQL server

My work company has a MSSQL server 2005. I have two questions about finding out current log user and any way to send out a warning message:
First question is if there is any T-SQL or SP available to find out current login user name and machine name. If the user is using SQL server sa name to remotely access to SQL server, is there any way to find out that user's windows name (the name to log to the windows)?
My next question is that if I can get the user name or id, is there any way to send out a warning message such as "currently SQL server is clean up or backup, please do not log in at this time". I guess it may be difficult. I may have to send an email out to the user.
The SQL server is only accessible in the company. The SQL server has a list of users as login users: windows users, SQL users and sa.
SELECT SUSER_SNAME(), HOST_NAME()
If the connection is "sa" (or any other SQL login) then you can't find the domain/windows user name. SQL Server only knows it's "sa" or that SQL login.
HOST_NAME may not be reliable either, it can be set in the connection string ("Application Name"). Or it could be vague eg "Microsoft Office" for by default for Access, Excel etc
You could backtrack via client_net_address in sys.dm_exec_connections and match MAC address to IP and find out who is logged on...
An easy way to find out both host and user is
EXEC sp_who2;
where you get some other information that can be good to know, as if the user is active and so on...
It does not resolve the issues that gbn announced.
Thanks for all your suggestions first. I tried all the methods and I think Joakim Backman's method meet my need. Here is summary of what I find out.
Query of sys.syslogins only list login information. The accdate does not give the current login user timestamp. I tried to login from another application to my SQL and this query does not list the login.
SELECT SUSER_SNAME(), HOST_NAME() only list one user on SQL server. For example, I log in in as my name to SQL server. The result of this query only lists my name and machine name. This query does not list current users on the SQL server.
exec sp_who2 lists information I need. It lists current user name machine name, active status, db name user's access, and command used.
In order to get the information I use in SP, I have to filter and join the information with other tables, such as emails. Here is the codes I use:
DECLARE #retTable TABLE (
SPID int not null
, Status varchar (255) not null
, Login varchar (255) not null
, HostName varchar (255) not null
, BlkBy varchar(10) not null
, DBName varchar (255) null
, Command varchar (255) not null
, CPUTime int not null
, DiskIO int not null
, LastBatch varchar (255) not null
, ProgramName varchar (255) null
, SPID2 int not null
, REQUESTID INT
)
INSERT INTO #retTable EXEC sp_who2
SELECT Status, Login, HostName, DBName, Command, CPUTime, ProgramName -- *
FROM #retTable
--WHERE Login not like 'sa%' -- if not interested in sa
ORDER BY Login, HostName