33
33
#include <Aclapi.h>
34
34
#include <lm.h>
35
35
#include <stdio.h>
36
+ #include <stdlib.h>
37
+ #include <string.h>
36
38
37
39
#include "inc\pwd.h"
38
40
#include "sshfileperm.h"
39
41
#include "debug.h"
40
42
#include "misc_internal.h"
41
43
#include "config.h"
42
44
45
+ #define NULL_TERMINATOR_LEN 1
46
+ #define COMMA_SPACE_LEN 2
47
+ #define BACKSLASH_LEN 1
48
+
49
+ extern int log_on_stderr ;
50
+
43
51
/*
44
52
* The function is to check if current user is secure to access to the file.
45
53
* Check the owner of the file is one of these types: Local Administrators groups, system account, current user account
@@ -178,37 +186,38 @@ check_secure_file_permission(const char *input_path, struct passwd * pw, int rea
178
186
* Check the owner of the file is one of these types: Local Administrators groups or system account
179
187
* Check the users have access permission to the file don't violate the following rules:
180
188
1. no user other than local administrators group and system account have write permission on the folder
181
- * Returns 0 on success and -1 on failure
189
+ * Logs a message if the rules are violated, but does not prevent further execution
182
190
*/
183
- int
191
+ void
184
192
check_secure_folder_permission (const wchar_t * path_utf16 , int read_ok )
185
193
{
186
194
PSECURITY_DESCRIPTOR pSD = NULL ;
187
195
PSID owner_sid = NULL , ti_sid = NULL ;
188
196
PACL dacl = NULL ;
189
197
DWORD error_code = ERROR_SUCCESS ;
190
- BOOL is_valid_sid = FALSE, is_valid_acl = FALSE;
198
+ BOOL is_valid_sid = FALSE, is_valid_acl = FALSE, need_log_msg = FALSE, is_first = TRUE ;
191
199
wchar_t * bad_user = NULL ;
192
- int ret = 0 ;
200
+ size_t log_msg_len = (DNLEN + BACKSLASH_LEN + UNLEN ) * 2 + COMMA_SPACE_LEN + NULL_TERMINATOR_LEN ;
201
+ wchar_t * log_msg = (wchar_t * )malloc (log_msg_len * sizeof (wchar_t ));
202
+ if (log_msg != NULL ) {
203
+ log_msg [0 ] = '\0' ;
204
+ }
193
205
194
206
/*Get the owner sid of the file.*/
195
207
if ((error_code = GetNamedSecurityInfoW (path_utf16 , SE_FILE_OBJECT ,
196
208
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION ,
197
209
& owner_sid , NULL , & dacl , NULL , & pSD )) != ERROR_SUCCESS ) {
198
210
printf ("failed to retrieve the owner sid and dacl of file %S with error code: %d" , path_utf16 , error_code );
199
211
errno = EOTHER ;
200
- ret = -1 ;
201
212
goto cleanup ;
202
213
}
203
214
if (((is_valid_sid = IsValidSid (owner_sid )) == FALSE) || ((is_valid_acl = IsValidAcl (dacl )) == FALSE)) {
204
215
printf ("IsValidSid: %d; is_valid_acl: %d" , is_valid_sid , is_valid_acl );
205
- ret = -1 ;
206
216
goto cleanup ;
207
217
}
208
218
if (!IsWellKnownSid (owner_sid , WinBuiltinAdministratorsSid ) &&
209
219
!IsWellKnownSid (owner_sid , WinLocalSystemSid )) {
210
220
printf ("Bad owner on %S" , path_utf16 );
211
- ret = -1 ;
212
221
goto cleanup ;
213
222
}
214
223
/*
@@ -224,7 +233,6 @@ check_secure_folder_permission(const wchar_t* path_utf16, int read_ok)
224
233
if (!GetAce (dacl , i , & current_ace )) {
225
234
printf ("GetAce() failed" );
226
235
errno = EOTHER ;
227
- ret = -1 ;
228
236
goto cleanup ;
229
237
}
230
238
@@ -247,15 +255,112 @@ check_secure_folder_permission(const wchar_t* path_utf16, int read_ok)
247
255
continue ;
248
256
}
249
257
else {
250
- ret = -1 ;
258
+ /* collect all SIDs with write permissions */
259
+ wchar_t resolved_trustee [UNLEN + NULL_TERMINATOR_LEN ] = L"UNKNOWN" ;
260
+ wchar_t resolved_trustee_domain [DNLEN + NULL_TERMINATOR_LEN ] = L"UNKNOWN" ;
261
+ DWORD resolved_trustee_len = _countof (resolved_trustee ), resolved_trustee_domain_len = _countof (resolved_trustee_domain );
262
+ SID_NAME_USE resolved_trustee_type ;
263
+
264
+ need_log_msg = TRUE;
265
+
266
+ if (log_msg != NULL &&
267
+ LookupAccountSidW (NULL , current_trustee_sid , resolved_trustee , & resolved_trustee_len ,
268
+ resolved_trustee_domain , & resolved_trustee_domain_len , & resolved_trustee_type ) != 0 ) {
269
+ if (is_first ) {
270
+ _snwprintf_s (log_msg , log_msg_len , _TRUNCATE , L"%ls\\%ls" , resolved_trustee_domain , resolved_trustee );
271
+ is_first = FALSE;
272
+ }
273
+ else {
274
+ size_t currentLength = wcslen (log_msg );
275
+ size_t userLength = resolved_trustee_domain_len + BACKSLASH_LEN + resolved_trustee_len + COMMA_SPACE_LEN ;
276
+ if (wcslen (log_msg ) + userLength + NULL_TERMINATOR_LEN > log_msg_len ) {
277
+ log_msg_len *= 2 ;
278
+ wchar_t * temp_log_msg = (wchar_t * )malloc (log_msg_len * sizeof (wchar_t ));
279
+ if (temp_log_msg == NULL ) {
280
+ break ;
281
+ }
282
+ wcscpy_s (temp_log_msg , log_msg_len , log_msg );
283
+ if (log_msg )
284
+ free (log_msg );
285
+ log_msg = temp_log_msg ;
286
+ }
287
+ _snwprintf_s (log_msg + currentLength , log_msg_len - currentLength , _TRUNCATE ,
288
+ L", %ls\\%ls" , resolved_trustee_domain , resolved_trustee );
289
+ }
290
+ }
251
291
}
252
292
}
293
+
294
+ if (need_log_msg ) {
295
+ log_folder_perms_msg_etw (path_utf16 , log_msg );
296
+ }
253
297
cleanup :
254
- if (bad_user )
298
+ if (bad_user ) {
255
299
LocalFree (bad_user );
256
- if (pSD )
300
+ }
301
+ if (log_msg ) {
302
+ free (log_msg );
303
+ }
304
+ if (pSD ) {
257
305
LocalFree (pSD );
258
- if (ti_sid )
306
+ }
307
+ if (ti_sid ) {
259
308
free (ti_sid );
260
- return ret ;
309
+ }
310
+ }
311
+
312
+ /*
313
+ * This function takes in the full path to the ProgramData\ssh folder
314
+ * and a string of comma-separated domain\usernames. The function converts
315
+ * the well-known built-in Administrators group sid and the Local System
316
+ * sid to their corresponding names. With these names, and the input string,
317
+ * it logs a message to the Event Viewer. If logging the detailed message fails,
318
+ * a generic log message is written to the Event Viewer instead.
319
+ */
320
+ void log_folder_perms_msg_etw (const wchar_t * path_utf16 , wchar_t * log_msg ) {
321
+ PSID adminSid = NULL ;
322
+ WCHAR adminName [UNLEN + NULL_TERMINATOR_LEN ];
323
+ WCHAR adminDomain [DNLEN + NULL_TERMINATOR_LEN ];
324
+ DWORD adminNameSize = UNLEN + NULL_TERMINATOR_LEN ;
325
+ DWORD adminDomainSize = DNLEN + NULL_TERMINATOR_LEN ;
326
+ DWORD adminSidSize = SECURITY_MAX_SID_SIZE ;
327
+ PSID systemSid = NULL ;
328
+ WCHAR systemName [UNLEN + NULL_TERMINATOR_LEN ];
329
+ WCHAR systemDomain [DNLEN + NULL_TERMINATOR_LEN ];
330
+ DWORD systemNameSize = UNLEN + NULL_TERMINATOR_LEN ;
331
+ DWORD systemDomainSize = DNLEN + NULL_TERMINATOR_LEN ;
332
+ DWORD systemSidSize = SECURITY_MAX_SID_SIZE ;
333
+ SID_NAME_USE sidType ;
334
+ BOOL needLog = TRUE;
335
+ int temp_log_on_stderr = log_on_stderr ;
336
+ log_on_stderr = 0 ;
337
+
338
+ adminSid = (PSID )malloc (SECURITY_MAX_SID_SIZE );
339
+ if (log_msg != NULL && adminSid != NULL &&
340
+ CreateWellKnownSid (WinBuiltinAdministratorsSid , NULL , adminSid , & adminSidSize ) != 0 &&
341
+ LookupAccountSidW (NULL , adminSid , adminName , & adminNameSize , adminDomain , & adminDomainSize , & sidType ) != 0 ) {
342
+ systemSid = (PSID )malloc (SECURITY_MAX_SID_SIZE );
343
+ if (systemSid != NULL &&
344
+ CreateWellKnownSid (WinLocalSystemSid , NULL , systemSid , & systemSidSize ) != 0 &&
345
+ LookupAccountSidW (NULL , systemSid , systemName , & systemNameSize , systemDomain , & systemDomainSize , & sidType ) != 0 ) {
346
+ logit ("For '%S' folder, write access is granted to the following users: %S. "
347
+ "Consider reviewing users to ensure that only %S\\%S, and the %S\\%S group, and its members, have write access." ,
348
+ path_utf16 , log_msg , systemDomain , systemName , adminDomain , adminName );
349
+ needLog = FALSE;
350
+ }
351
+ }
352
+
353
+ if (needLog ) {
354
+ /* log generic warning message in unlikely case that lookup for either well-known SID fails or user list is empty */
355
+ logit ("for '%S' folder, consider downgrading permissions for any users with unnecessary write access." , path_utf16 );
356
+ }
357
+
358
+ log_on_stderr = temp_log_on_stderr ;
359
+
360
+ if (adminSid ) {
361
+ free (adminSid );
362
+ }
363
+ if (systemSid ) {
364
+ free (systemSid );
365
+ }
261
366
}
0 commit comments