Author: akhaldi
Date: Fri Oct 24 16:52:57 2014
New Revision: 64962
URL:
http://svn.reactos.org/svn/reactos?rev=64962&view=rev
Log:
[ADVAPI32]
* Move some functions from token.c to security.c.
CORE-8540
Modified:
trunk/reactos/dll/win32/advapi32/token/token.c
trunk/reactos/dll/win32/advapi32/wine/security.c
Modified: trunk/reactos/dll/win32/advapi32/token/token.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/token/t…
==============================================================================
--- trunk/reactos/dll/win32/advapi32/token/token.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/advapi32/token/token.c [iso-8859-1] Fri Oct 24 16:52:57 2014
@@ -13,357 +13,6 @@
#include <ndk/setypes.h>
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
-
-/*
- * @implemented
- */
-BOOL WINAPI
-AdjustTokenGroups(HANDLE TokenHandle,
- BOOL ResetToDefault,
- PTOKEN_GROUPS NewState,
- DWORD BufferLength,
- PTOKEN_GROUPS PreviousState,
- PDWORD ReturnLength)
-{
- NTSTATUS Status;
-
- Status = NtAdjustGroupsToken(TokenHandle,
- ResetToDefault,
- NewState,
- BufferLength,
- PreviousState,
- (PULONG)ReturnLength);
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-AdjustTokenPrivileges(HANDLE TokenHandle,
- BOOL DisableAllPrivileges,
- PTOKEN_PRIVILEGES NewState,
- DWORD BufferLength,
- PTOKEN_PRIVILEGES PreviousState,
- PDWORD ReturnLength)
-{
- NTSTATUS Status;
-
- Status = NtAdjustPrivilegesToken(TokenHandle,
- DisableAllPrivileges,
- NewState,
- BufferLength,
- PreviousState,
- (PULONG)ReturnLength);
- if (STATUS_NOT_ALL_ASSIGNED == Status)
- {
- SetLastError(ERROR_NOT_ALL_ASSIGNED);
- return TRUE;
- }
-
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- /* AdjustTokenPrivileges is documented to do this */
- SetLastError(ERROR_SUCCESS);
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-GetTokenInformation(HANDLE TokenHandle,
- TOKEN_INFORMATION_CLASS TokenInformationClass,
- LPVOID TokenInformation,
- DWORD TokenInformationLength,
- PDWORD ReturnLength)
-{
- NTSTATUS Status;
-
- Status = NtQueryInformationToken(TokenHandle,
- TokenInformationClass,
- TokenInformation,
- TokenInformationLength,
- (PULONG)ReturnLength);
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-SetTokenInformation(HANDLE TokenHandle,
- TOKEN_INFORMATION_CLASS TokenInformationClass,
- LPVOID TokenInformation,
- DWORD TokenInformationLength)
-{
- NTSTATUS Status;
-
- Status = NtSetInformationToken(TokenHandle,
- TokenInformationClass,
- TokenInformation,
- TokenInformationLength);
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
- IN HANDLE ClientToken,
- IN DWORD DesiredAccess,
- IN PGENERIC_MAPPING GenericMapping,
- OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
- IN OUT LPDWORD PrivilegeSetLength,
- OUT LPDWORD GrantedAccess,
- OUT LPBOOL AccessStatus)
-{
- NTSTATUS Status;
- NTSTATUS NtAccessStatus;
-
- /* Do the access check */
- Status = NtAccessCheck(pSecurityDescriptor,
- ClientToken,
- DesiredAccess,
- GenericMapping,
- PrivilegeSet,
- (PULONG)PrivilegeSetLength,
- (PACCESS_MASK)GrantedAccess,
- &NtAccessStatus);
-
- /* See if the access check operation succeeded */
- if (!NT_SUCCESS(Status))
- {
- /* Check failed */
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- /* Now check the access status */
- if (!NT_SUCCESS(NtAccessStatus))
- {
- /* Access denied */
- SetLastError(RtlNtStatusToDosError(NtAccessStatus));
- *AccessStatus = FALSE;
- }
- else
- {
- /* Access granted */
- *AccessStatus = TRUE;
- }
-
- /* Check succeeded */
- return TRUE;
-}
-
-/*
- * @unimplemented
- */
-BOOL WINAPI AccessCheckByType(
- PSECURITY_DESCRIPTOR pSecurityDescriptor,
- PSID PrincipalSelfSid,
- HANDLE ClientToken,
- DWORD DesiredAccess,
- POBJECT_TYPE_LIST ObjectTypeList,
- DWORD ObjectTypeListLength,
- PGENERIC_MAPPING GenericMapping,
- PPRIVILEGE_SET PrivilegeSet,
- LPDWORD PrivilegeSetLength,
- LPDWORD GrantedAccess,
- LPBOOL AccessStatus)
-{
- FIXME("stub\n");
-
- *AccessStatus = TRUE;
-
- return !*AccessStatus;
-}
-
-/*
- * @implemented
- */
-BOOL WINAPI
-OpenProcessToken(HANDLE ProcessHandle,
- DWORD DesiredAccess,
- PHANDLE TokenHandle)
-{
- NTSTATUS Status;
-
- TRACE("%p, %x, %p.\n", ProcessHandle, DesiredAccess, TokenHandle);
-
- Status = NtOpenProcessToken(ProcessHandle,
- DesiredAccess,
- TokenHandle);
- if (!NT_SUCCESS(Status))
- {
- ERR("NtOpenProcessToken failed! Status %08x.\n", Status);
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- TRACE("Returning token %p.\n", *TokenHandle);
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-OpenThreadToken(HANDLE ThreadHandle,
- DWORD DesiredAccess,
- BOOL OpenAsSelf,
- PHANDLE TokenHandle)
-{
- NTSTATUS Status;
-
- Status = NtOpenThreadToken(ThreadHandle,
- DesiredAccess,
- OpenAsSelf,
- TokenHandle);
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL,
- IN HANDLE TokenHandle)
-{
- NTSTATUS Status;
- HANDLE hThread;
-
- hThread = (ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread();
-
- Status = NtSetInformationThread(hThread,
- ThreadImpersonationToken,
- &TokenHandle,
- sizeof(HANDLE));
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-DuplicateTokenEx(IN HANDLE ExistingTokenHandle,
- IN DWORD dwDesiredAccess,
- IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL,
- IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- IN TOKEN_TYPE TokenType,
- OUT PHANDLE DuplicateTokenHandle)
-{
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status;
- SECURITY_QUALITY_OF_SERVICE Sqos;
-
- TRACE("%p 0x%08x 0x%08x 0x%08x %p\n", ExistingTokenHandle,
dwDesiredAccess,
- ImpersonationLevel, TokenType, DuplicateTokenHandle);
-
- Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
- Sqos.ImpersonationLevel = ImpersonationLevel;
- Sqos.ContextTrackingMode = 0;
- Sqos.EffectiveOnly = FALSE;
-
- if (lpTokenAttributes != NULL)
- {
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- lpTokenAttributes->bInheritHandle ? OBJ_INHERIT :
0,
- NULL,
- lpTokenAttributes->lpSecurityDescriptor);
- }
- else
- {
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- 0,
- NULL,
- NULL);
- }
-
- ObjectAttributes.SecurityQualityOfService = &Sqos;
-
- Status = NtDuplicateToken(ExistingTokenHandle,
- dwDesiredAccess,
- &ObjectAttributes,
- FALSE,
- TokenType,
- DuplicateTokenHandle);
- if (!NT_SUCCESS(Status))
- {
- ERR("NtDuplicateToken failed: Status %08x\n", Status);
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- TRACE("Returning token %p.\n", *DuplicateTokenHandle);
-
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL WINAPI
-DuplicateToken(IN HANDLE ExistingTokenHandle,
- IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- OUT PHANDLE DuplicateTokenHandle)
-{
- return DuplicateTokenEx(ExistingTokenHandle,
- TOKEN_IMPERSONATE | TOKEN_QUERY,
- NULL,
- ImpersonationLevel,
- TokenImpersonation,
- DuplicateTokenHandle);
-}
-
/*
* @implemented
@@ -616,23 +265,6 @@
return Ret;
}
-
-
-BOOL WINAPI
-CreateRestrictedToken(HANDLE TokenHandle,
- DWORD Flags,
- DWORD DisableSidCount,
- PSID_AND_ATTRIBUTES pSidAndAttributes,
- DWORD DeletePrivilegeCount,
- PLUID_AND_ATTRIBUTES pLUIDAndAttributes,
- DWORD RestrictedSidCount,
- PSID_AND_ATTRIBUTES pSIDAndAttributes,
- PHANDLE NewTokenHandle)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
-
/*
* @unimplemented
@@ -711,20 +343,3 @@
RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSids);
return PSiteSid;
}
-
-
-BOOL
-WINAPI
-CreateProcessWithTokenW(IN HANDLE hToken,
- IN DWORD dwLogonFlags,
- IN LPCWSTR lpApplicationName OPTIONAL,
- IN OUT LPWSTR lpCommandLine OPTIONAL,
- IN DWORD dwCreationFlags,
- IN LPVOID lpEnvironment OPTIONAL,
- IN LPCWSTR lpCurrentDirectory OPTIONAL,
- IN LPSTARTUPINFOW lpStartupInfo,
- OUT LPPROCESS_INFORMATION lpProcessInfo)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
Modified: trunk/reactos/dll/win32/advapi32/wine/security.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/wine/se…
==============================================================================
--- trunk/reactos/dll/win32/advapi32/wine/security.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/advapi32/wine/security.c [iso-8859-1] Fri Oct 24 16:52:57
2014
@@ -317,6 +317,212 @@
* @implemented
*/
BOOL WINAPI
+OpenProcessToken(HANDLE ProcessHandle,
+ DWORD DesiredAccess,
+ PHANDLE TokenHandle)
+{
+ NTSTATUS Status;
+
+ TRACE("%p, %x, %p.\n", ProcessHandle, DesiredAccess, TokenHandle);
+
+ Status = NtOpenProcessToken(ProcessHandle,
+ DesiredAccess,
+ TokenHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("NtOpenProcessToken failed! Status %08x.\n", Status);
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ TRACE("Returning token %p.\n", *TokenHandle);
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+OpenThreadToken(HANDLE ThreadHandle,
+ DWORD DesiredAccess,
+ BOOL OpenAsSelf,
+ PHANDLE TokenHandle)
+{
+ NTSTATUS Status;
+
+ Status = NtOpenThreadToken(ThreadHandle,
+ DesiredAccess,
+ OpenAsSelf,
+ TokenHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AdjustTokenGroups(HANDLE TokenHandle,
+ BOOL ResetToDefault,
+ PTOKEN_GROUPS NewState,
+ DWORD BufferLength,
+ PTOKEN_GROUPS PreviousState,
+ PDWORD ReturnLength)
+{
+ NTSTATUS Status;
+
+ Status = NtAdjustGroupsToken(TokenHandle,
+ ResetToDefault,
+ NewState,
+ BufferLength,
+ PreviousState,
+ (PULONG)ReturnLength);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AdjustTokenPrivileges(HANDLE TokenHandle,
+ BOOL DisableAllPrivileges,
+ PTOKEN_PRIVILEGES NewState,
+ DWORD BufferLength,
+ PTOKEN_PRIVILEGES PreviousState,
+ PDWORD ReturnLength)
+{
+ NTSTATUS Status;
+
+ Status = NtAdjustPrivilegesToken(TokenHandle,
+ DisableAllPrivileges,
+ NewState,
+ BufferLength,
+ PreviousState,
+ (PULONG)ReturnLength);
+ if (STATUS_NOT_ALL_ASSIGNED == Status)
+ {
+ SetLastError(ERROR_NOT_ALL_ASSIGNED);
+ return TRUE;
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ /* AdjustTokenPrivileges is documented to do this */
+ SetLastError(ERROR_SUCCESS);
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetTokenInformation(HANDLE TokenHandle,
+ TOKEN_INFORMATION_CLASS TokenInformationClass,
+ LPVOID TokenInformation,
+ DWORD TokenInformationLength,
+ PDWORD ReturnLength)
+{
+ NTSTATUS Status;
+
+ Status = NtQueryInformationToken(TokenHandle,
+ TokenInformationClass,
+ TokenInformation,
+ TokenInformationLength,
+ (PULONG)ReturnLength);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SetTokenInformation(HANDLE TokenHandle,
+ TOKEN_INFORMATION_CLASS TokenInformationClass,
+ LPVOID TokenInformation,
+ DWORD TokenInformationLength)
+{
+ NTSTATUS Status;
+
+ Status = NtSetInformationToken(TokenHandle,
+ TokenInformationClass,
+ TokenInformation,
+ TokenInformationLength);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL,
+ IN HANDLE TokenHandle)
+{
+ NTSTATUS Status;
+ HANDLE hThread;
+
+ hThread = (ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread();
+
+ Status = NtSetInformationThread(hThread,
+ ThreadImpersonationToken,
+ &TokenHandle,
+ sizeof(HANDLE));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI
+CreateRestrictedToken(HANDLE TokenHandle,
+ DWORD Flags,
+ DWORD DisableSidCount,
+ PSID_AND_ATTRIBUTES pSidAndAttributes,
+ DWORD DeletePrivilegeCount,
+ PLUID_AND_ATTRIBUTES pLUIDAndAttributes,
+ DWORD RestrictedSidCount,
+ PSID_AND_ATTRIBUTES pSIDAndAttributes,
+ PHANDLE NewTokenHandle)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
BYTE nSubAuthorityCount,
DWORD dwSubAuthority0,
@@ -591,6 +797,81 @@
GetLengthSid(PSID pSid)
{
return (DWORD)RtlLengthSid(pSid);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ IN HANDLE ClientToken,
+ IN DWORD DesiredAccess,
+ IN PGENERIC_MAPPING GenericMapping,
+ OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
+ IN OUT LPDWORD PrivilegeSetLength,
+ OUT LPDWORD GrantedAccess,
+ OUT LPBOOL AccessStatus)
+{
+ NTSTATUS Status;
+ NTSTATUS NtAccessStatus;
+
+ /* Do the access check */
+ Status = NtAccessCheck(pSecurityDescriptor,
+ ClientToken,
+ DesiredAccess,
+ GenericMapping,
+ PrivilegeSet,
+ (PULONG)PrivilegeSetLength,
+ (PACCESS_MASK)GrantedAccess,
+ &NtAccessStatus);
+
+ /* See if the access check operation succeeded */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check failed */
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ /* Now check the access status */
+ if (!NT_SUCCESS(NtAccessStatus))
+ {
+ /* Access denied */
+ SetLastError(RtlNtStatusToDosError(NtAccessStatus));
+ *AccessStatus = FALSE;
+ }
+ else
+ {
+ /* Access granted */
+ *AccessStatus = TRUE;
+ }
+
+ /* Check succeeded */
+ return TRUE;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL WINAPI AccessCheckByType(
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ PSID PrincipalSelfSid,
+ HANDLE ClientToken,
+ DWORD DesiredAccess,
+ POBJECT_TYPE_LIST ObjectTypeList,
+ DWORD ObjectTypeListLength,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength,
+ LPDWORD GrantedAccess,
+ LPBOOL AccessStatus)
+{
+ FIXME("stub\n");
+
+ *AccessStatus = TRUE;
+
+ return !*AccessStatus;
}
/**********************************************************************
@@ -1801,6 +2082,98 @@
return TRUE;
}
+BOOL
+WINAPI
+CreateProcessWithTokenW(IN HANDLE hToken,
+ IN DWORD dwLogonFlags,
+ IN LPCWSTR lpApplicationName OPTIONAL,
+ IN OUT LPWSTR lpCommandLine OPTIONAL,
+ IN DWORD dwCreationFlags,
+ IN LPVOID lpEnvironment OPTIONAL,
+ IN LPCWSTR lpCurrentDirectory OPTIONAL,
+ IN LPSTARTUPINFOW lpStartupInfo,
+ OUT LPPROCESS_INFORMATION lpProcessInfo)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+DuplicateTokenEx(IN HANDLE ExistingTokenHandle,
+ IN DWORD dwDesiredAccess,
+ IN LPSECURITY_ATTRIBUTES lpTokenAttributes OPTIONAL,
+ IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+ IN TOKEN_TYPE TokenType,
+ OUT PHANDLE DuplicateTokenHandle)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ SECURITY_QUALITY_OF_SERVICE Sqos;
+
+ TRACE("%p 0x%08x 0x%08x 0x%08x %p\n", ExistingTokenHandle,
dwDesiredAccess,
+ ImpersonationLevel, TokenType, DuplicateTokenHandle);
+
+ Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ Sqos.ImpersonationLevel = ImpersonationLevel;
+ Sqos.ContextTrackingMode = 0;
+ Sqos.EffectiveOnly = FALSE;
+
+ if (lpTokenAttributes != NULL)
+ {
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ lpTokenAttributes->bInheritHandle ? OBJ_INHERIT :
0,
+ NULL,
+ lpTokenAttributes->lpSecurityDescriptor);
+ }
+ else
+ {
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ }
+
+ ObjectAttributes.SecurityQualityOfService = &Sqos;
+
+ Status = NtDuplicateToken(ExistingTokenHandle,
+ dwDesiredAccess,
+ &ObjectAttributes,
+ FALSE,
+ TokenType,
+ DuplicateTokenHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("NtDuplicateToken failed: Status %08x\n", Status);
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ TRACE("Returning token %p.\n", *DuplicateTokenHandle);
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+DuplicateToken(IN HANDLE ExistingTokenHandle,
+ IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+ OUT PHANDLE DuplicateTokenHandle)
+{
+ return DuplicateTokenEx(ExistingTokenHandle,
+ TOKEN_IMPERSONATE | TOKEN_QUERY,
+ NULL,
+ ImpersonationLevel,
+ TokenImpersonation,
+ DuplicateTokenHandle);
+}
+
/*
* @implemented
*/