|
20 | 20 | */ |
21 | 21 |
|
22 | 22 | #include "LSGetAccountCommand.h" |
| 23 | +#import <openssl/sha.h> // hh(2025-04-25) will this build? |
23 | 24 |
|
24 | 25 | @class NSString, NSNumber; |
25 | 26 |
|
@@ -56,6 +57,54 @@ - (id)initWithUserDefaults:(NSUserDefaults *)_ud |
56 | 57 | andContext:(LSCommandContext *)_tx; |
57 | 58 | @end |
58 | 59 |
|
| 60 | +NSString *GetSHA512PasswordUpdate(NSString *plainPassword, NSString *companyId) |
| 61 | +{ |
| 62 | + const char *cstr = [plainPassword UTF8String]; |
| 63 | + unsigned char hash[SHA512_DIGEST_LENGTH]; |
| 64 | + SHA512((const unsigned char*)cstr, strlen(cstr), hash); |
| 65 | + |
| 66 | + NSMutableString *sha512 = |
| 67 | + [NSMutableString stringWithCapacity:SHA512_DIGEST_LENGTH * 2 + 8]; |
| 68 | + [sha512 appendString:@"{SHA512}"]; |
| 69 | + |
| 70 | + int i; |
| 71 | + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { |
| 72 | + [sha512 appendFormat:@"%02x", hash[i]]; |
| 73 | + } |
| 74 | + |
| 75 | + /* What we do here should be pretty safe wrt SQL injection given the |
| 76 | + * nature of the values. Would be better to do with the entity/adaptor |
| 77 | + * anyways */ |
| 78 | + NSMutableString *sql = [NSMutableString stringWithCapacity:256]; |
| 79 | + /* |
| 80 | + DO $$ |
| 81 | + BEGIN |
| 82 | + BEGIN |
| 83 | + EXECUTE 'UPDATE my_table SET missing_column = 42'; |
| 84 | + EXCEPTION |
| 85 | + WHEN undefined_column THEN |
| 86 | + RAISE NOTICE 'Column does not exist, update skipped.'; |
| 87 | + END; |
| 88 | + END; |
| 89 | + $$;*/ |
| 90 | + [sql appendString:@"DO $$ BEGIN BEGIN EXECUTE '"]; |
| 91 | + |
| 92 | + [sql appendString:@"UPDATE person SET modern_password = ''"]; |
| 93 | + [sql appendString:sha512]; |
| 94 | + [sql appendString:@"'' WHERE company_id = "]; |
| 95 | + [sql appendString:companyId]; |
| 96 | + [sql appendString:@" AND (modern_password != ''"]; |
| 97 | + [sql appendString:sha512]; |
| 98 | + [sql appendString:@"'' OR modern_password IS NULL)"]; |
| 99 | + |
| 100 | + [sql appendString:@"'; "]; |
| 101 | + |
| 102 | + [sql appendString:@"EXCEPTION WHEN undefined_column THEN "]; |
| 103 | + [sql appendString:@"RAISE NOTICE 'Column does not exist, update skipped.'; "]; |
| 104 | + [sql appendString:@"END; END; $$;"]; |
| 105 | + return sql; |
| 106 | +} |
| 107 | + |
59 | 108 | @implementation LSLoginAccountCommand |
60 | 109 |
|
61 | 110 | - (id)initForOperation:(NSString *)_operation inDomain:(NSString *)_domain { |
@@ -120,7 +169,7 @@ - (void)_executeInContext:(id)_context { |
120 | 169 | qualifierFormat: |
121 | 170 | @"login='%@' AND isAccount=1 AND " |
122 | 171 | @"(NOT login='template') AND " |
123 | | - @"(isLocked=0 OR isLocked is null)", |
| 172 | + @"(isLocked=0 OR isLocked IS NULL)", |
124 | 173 | userName]; |
125 | 174 | isArchivedQualifier = |
126 | 175 | [[EOSQLQualifier alloc] initWithEntity:[self entity] |
@@ -186,14 +235,14 @@ - (void)_executeInContext:(id)_context { |
186 | 235 | } |
187 | 236 | } |
188 | 237 | else { /* use table for authorization */ |
189 | | - NSString *cryptedPwd = nil; |
190 | | - id accountPassword; |
191 | | - |
192 | | - accountPassword = [account valueForKey:@"password"]; |
193 | | - |
| 238 | + |
| 239 | + // This is the hashed password in the account. |
| 240 | + id accountPassword = [account valueForKey:@"password"]; |
194 | 241 | if (accountPassword == nil) |
195 | 242 | accountPassword = @""; |
196 | | - |
| 243 | + |
| 244 | + // The crypted version of the password. |
| 245 | + NSString *cryptedPwd = nil; |
197 | 246 | if (![self->crypted boolValue] && [[self password] isNotEmpty]) { |
198 | 247 | id cmd = LSLookupCommandV(@"system", @"crypt", |
199 | 248 | @"password", [self password], |
@@ -232,6 +281,25 @@ - (void)_executeInContext:(id)_context { |
232 | 281 | if (account) { |
233 | 282 | NSUserDefaults *defs; |
234 | 283 |
|
| 284 | + // 2025-04-25: |
| 285 | + // HH: Persist a better hash. |
| 286 | + // We could also upgrade from crypt to SHA512, but for that we would need |
| 287 | + // to support this everywhere, doesn't seem worthwile, just yet? Move Auth |
| 288 | + // out of OGo itself into Apache instead? |
| 289 | + // TODO: protect by default |
| 290 | + if (![self->crypted boolValue]) { |
| 291 | + NSString *sql = GetSHA512PasswordUpdate( |
| 292 | + [self password], [[account valueForKey:@"companyId"] stringValue]); |
| 293 | + |
| 294 | + EOAdaptorChannel *adChannel = [[self databaseChannel] adaptorChannel]; |
| 295 | + id error; |
| 296 | + if ((error = [adChannel evaluateExpressionX:sql]) != nil) { |
| 297 | + [self errorWithFormat:@"Couldn't write modern_password: %@", error]; |
| 298 | + } |
| 299 | + } |
| 300 | + |
| 301 | + |
| 302 | + |
235 | 303 | /* load defaults */ |
236 | 304 |
|
237 | 305 | Class defaultsClass = NGClassFromString(@"LSUserDefaults"); |
|
0 commit comments