/src/samba/source3/passdb/account_pol.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * account policy storage |
4 | | * Copyright (C) Jean François Micouleau 1998-2001 |
5 | | * Copyright (C) Andrew Bartlett 2002 |
6 | | * Copyright (C) Guenther Deschner 2004-2005 |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 3 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | #include "includes.h" |
23 | | #include "system/filesys.h" |
24 | | #include "passdb.h" |
25 | | #include "dbwrap/dbwrap.h" |
26 | | #include "dbwrap/dbwrap_open.h" |
27 | | #include "../libcli/security/security.h" |
28 | | #include "lib/privileges.h" |
29 | | #include "lib/gencache.h" |
30 | | #include "lib/util/smb_strtox.h" |
31 | | |
32 | | static struct db_context *db; |
33 | | |
34 | | /* cache all entries for 60 seconds for to save ldap-queries (cache is updated |
35 | | * after this period if admins do not use pdbedit or usermanager but manipulate |
36 | | * ldap directly) - gd */ |
37 | | |
38 | 0 | #define DATABASE_VERSION 3 |
39 | 0 | #define AP_TTL 60 |
40 | | |
41 | | |
42 | | struct ap_table { |
43 | | enum pdb_policy_type type; |
44 | | const char *string; |
45 | | uint32_t default_val; |
46 | | const char *description; |
47 | | const char *ldap_attr; |
48 | | }; |
49 | | |
50 | | static const struct ap_table account_policy_names[] = { |
51 | | {PDB_POLICY_MIN_PASSWORD_LEN, "min password length", MINPASSWDLENGTH, |
52 | | "Minimal password length (default: 5)", |
53 | | "sambaMinPwdLength" }, |
54 | | |
55 | | {PDB_POLICY_PASSWORD_HISTORY, "password history", 0, |
56 | | "Length of Password History Entries (default: 0 => off)", |
57 | | "sambaPwdHistoryLength" }, |
58 | | |
59 | | {PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, "user must logon to change password", 0, |
60 | | "Force Users to logon for password change (default: 0 => off, 2 => on)", |
61 | | "sambaLogonToChgPwd" }, |
62 | | |
63 | | {PDB_POLICY_MAX_PASSWORD_AGE, "maximum password age", (uint32_t) -1, |
64 | | "Maximum password age, in seconds (default: -1 => never expire passwords)", |
65 | | "sambaMaxPwdAge" }, |
66 | | |
67 | | {PDB_POLICY_MIN_PASSWORD_AGE,"minimum password age", 0, |
68 | | "Minimal password age, in seconds (default: 0 => allow immediate password change)", |
69 | | "sambaMinPwdAge" }, |
70 | | |
71 | | {PDB_POLICY_LOCK_ACCOUNT_DURATION, "lockout duration", 30, |
72 | | "Lockout duration in minutes (default: 30, -1 => forever)", |
73 | | "sambaLockoutDuration" }, |
74 | | |
75 | | {PDB_POLICY_RESET_COUNT_TIME, "reset count minutes", 30, |
76 | | "Reset time after lockout in minutes (default: 30)", |
77 | | "sambaLockoutObservationWindow" }, |
78 | | |
79 | | {PDB_POLICY_BAD_ATTEMPT_LOCKOUT, "bad lockout attempt", 0, |
80 | | "Lockout users after bad logon attempts (default: 0 => off)", |
81 | | "sambaLockoutThreshold" }, |
82 | | |
83 | | {PDB_POLICY_TIME_TO_LOGOUT, "disconnect time", (uint32_t) -1, |
84 | | "Disconnect Users outside logon hours (default: -1 => off, 0 => on)", |
85 | | "sambaForceLogoff" }, |
86 | | |
87 | | {PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, "refuse machine password change", 0, |
88 | | "Allow Machine Password changes (default: 0 => off)", |
89 | | "sambaRefuseMachinePwdChange" }, |
90 | | |
91 | | {0, NULL, 0, "", NULL} |
92 | | }; |
93 | | |
94 | | void account_policy_names_list(TALLOC_CTX *mem_ctx, const char ***names, int *num_names) |
95 | 0 | { |
96 | 0 | const char **nl; |
97 | 0 | int i, count = ARRAY_SIZE(account_policy_names); |
98 | |
|
99 | 0 | nl = talloc_array(mem_ctx, const char *, count); |
100 | 0 | if (!nl) { |
101 | 0 | *num_names = 0; |
102 | 0 | return; |
103 | 0 | } |
104 | 0 | for (i=0; i<count; i++) { |
105 | 0 | nl[i] = account_policy_names[i].string; |
106 | 0 | } |
107 | | /* Do not return the last null entry */ |
108 | 0 | *num_names = count-1; |
109 | 0 | *names = nl; |
110 | 0 | return; |
111 | 0 | } |
112 | | |
113 | | /**************************************************************************** |
114 | | Get the account policy name as a string from its #define'ed number |
115 | | ****************************************************************************/ |
116 | | |
117 | | const char *decode_account_policy_name(enum pdb_policy_type type) |
118 | 0 | { |
119 | 0 | int i; |
120 | 0 | for (i=0; account_policy_names[i].string; i++) { |
121 | 0 | if (type == account_policy_names[i].type) { |
122 | 0 | return account_policy_names[i].string; |
123 | 0 | } |
124 | 0 | } |
125 | 0 | return NULL; |
126 | 0 | } |
127 | | |
128 | | /**************************************************************************** |
129 | | Get the account policy LDAP attribute as a string from its #define'ed number |
130 | | ****************************************************************************/ |
131 | | |
132 | | const char *get_account_policy_attr(enum pdb_policy_type type) |
133 | 0 | { |
134 | 0 | int i; |
135 | 0 | for (i=0; account_policy_names[i].type; i++) { |
136 | 0 | if (type == account_policy_names[i].type) { |
137 | 0 | return account_policy_names[i].ldap_attr; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | return NULL; |
141 | 0 | } |
142 | | |
143 | | /**************************************************************************** |
144 | | Get the account policy description as a string from its #define'ed number |
145 | | ****************************************************************************/ |
146 | | |
147 | | const char *account_policy_get_desc(enum pdb_policy_type type) |
148 | 0 | { |
149 | 0 | int i; |
150 | 0 | for (i=0; account_policy_names[i].string; i++) { |
151 | 0 | if (type == account_policy_names[i].type) { |
152 | 0 | return account_policy_names[i].description; |
153 | 0 | } |
154 | 0 | } |
155 | 0 | return NULL; |
156 | 0 | } |
157 | | |
158 | | /**************************************************************************** |
159 | | Get the account policy name as a string from its #define'ed number |
160 | | ****************************************************************************/ |
161 | | |
162 | | enum pdb_policy_type account_policy_name_to_typenum(const char *name) |
163 | 0 | { |
164 | 0 | int i; |
165 | 0 | for (i=0; account_policy_names[i].string; i++) { |
166 | 0 | if (strcmp(name, account_policy_names[i].string) == 0) { |
167 | 0 | return account_policy_names[i].type; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | return 0; |
171 | 0 | } |
172 | | |
173 | | /***************************************************************************** |
174 | | Get default value for account policy |
175 | | *****************************************************************************/ |
176 | | |
177 | | bool account_policy_get_default(enum pdb_policy_type type, uint32_t *val) |
178 | 0 | { |
179 | 0 | int i; |
180 | 0 | for (i=0; account_policy_names[i].type; i++) { |
181 | 0 | if (account_policy_names[i].type == type) { |
182 | 0 | *val = account_policy_names[i].default_val; |
183 | 0 | return True; |
184 | 0 | } |
185 | 0 | } |
186 | 0 | DEBUG(0,("no default for account_policy index %d found. This should never happen\n", |
187 | 0 | type)); |
188 | 0 | return False; |
189 | 0 | } |
190 | | |
191 | | /***************************************************************************** |
192 | | Set default for a type if it is empty |
193 | | *****************************************************************************/ |
194 | | |
195 | | static bool account_policy_set_default_on_empty(enum pdb_policy_type type) |
196 | 0 | { |
197 | |
|
198 | 0 | uint32_t value; |
199 | |
|
200 | 0 | if (!account_policy_get(type, &value) && |
201 | 0 | !account_policy_get_default(type, &value)) { |
202 | 0 | return False; |
203 | 0 | } |
204 | | |
205 | 0 | return account_policy_set(type, value); |
206 | 0 | } |
207 | | |
208 | | /***************************************************************************** |
209 | | Open the account policy tdb. |
210 | | ***`*************************************************************************/ |
211 | | |
212 | | bool init_account_policy(void) |
213 | 0 | { |
214 | |
|
215 | 0 | const char *vstring = "INFO/version"; |
216 | 0 | uint32_t version = 0; |
217 | 0 | int i; |
218 | 0 | NTSTATUS status; |
219 | 0 | char *db_path; |
220 | |
|
221 | 0 | if (db != NULL) { |
222 | 0 | return True; |
223 | 0 | } |
224 | | |
225 | 0 | db_path = state_path(talloc_tos(), "account_policy.tdb"); |
226 | 0 | if (db_path == NULL) { |
227 | 0 | return false; |
228 | 0 | } |
229 | | |
230 | 0 | db = db_open(NULL, db_path, 0, TDB_DEFAULT, |
231 | 0 | O_RDWR, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); |
232 | |
|
233 | 0 | if (db == NULL) { /* the account policies files does not exist or open |
234 | | * failed, try to create a new one */ |
235 | 0 | db = db_open(NULL, db_path, 0, |
236 | 0 | TDB_DEFAULT, O_RDWR|O_CREAT, 0600, |
237 | 0 | DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); |
238 | 0 | if (db == NULL) { |
239 | 0 | DEBUG(0,("Failed to open account policy database\n")); |
240 | 0 | TALLOC_FREE(db_path); |
241 | 0 | return False; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | TALLOC_FREE(db_path); |
245 | |
|
246 | 0 | status = dbwrap_fetch_uint32_bystring(db, vstring, &version); |
247 | 0 | if (!NT_STATUS_IS_OK(status)) { |
248 | 0 | version = 0; |
249 | 0 | } |
250 | |
|
251 | 0 | if (version == DATABASE_VERSION) { |
252 | 0 | return true; |
253 | 0 | } |
254 | | |
255 | | /* handle a Samba upgrade */ |
256 | | |
257 | 0 | if (dbwrap_transaction_start(db) != 0) { |
258 | 0 | DEBUG(0, ("transaction_start failed\n")); |
259 | 0 | TALLOC_FREE(db); |
260 | 0 | return false; |
261 | 0 | } |
262 | | |
263 | 0 | status = dbwrap_fetch_uint32_bystring(db, vstring, &version); |
264 | 0 | if (!NT_STATUS_IS_OK(status)) { |
265 | 0 | version = 0; |
266 | 0 | } |
267 | |
|
268 | 0 | if (version == DATABASE_VERSION) { |
269 | | /* |
270 | | * Race condition |
271 | | */ |
272 | 0 | if (dbwrap_transaction_cancel(db)) { |
273 | 0 | smb_panic("transaction_cancel failed"); |
274 | 0 | } |
275 | 0 | return true; |
276 | 0 | } |
277 | | |
278 | 0 | if (version != DATABASE_VERSION) { |
279 | 0 | status = dbwrap_store_uint32_bystring(db, vstring, |
280 | 0 | DATABASE_VERSION); |
281 | 0 | if (!NT_STATUS_IS_OK(status)) { |
282 | 0 | DEBUG(0, ("dbwrap_store_uint32_t failed: %s\n", |
283 | 0 | nt_errstr(status))); |
284 | 0 | goto cancel; |
285 | 0 | } |
286 | | |
287 | 0 | for (i=0; account_policy_names[i].type; i++) { |
288 | |
|
289 | 0 | if (!account_policy_set_default_on_empty(account_policy_names[i].type)) { |
290 | 0 | DEBUG(0,("failed to set default value in account policy tdb\n")); |
291 | 0 | goto cancel; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | /* These exist by default on NT4 in [HKLM\SECURITY\Policy\Accounts] */ |
297 | | |
298 | 0 | privilege_create_account( &global_sid_World ); |
299 | 0 | privilege_create_account( &global_sid_Builtin_Account_Operators ); |
300 | 0 | privilege_create_account( &global_sid_Builtin_Server_Operators ); |
301 | 0 | privilege_create_account( &global_sid_Builtin_Print_Operators ); |
302 | 0 | privilege_create_account( &global_sid_Builtin_Backup_Operators ); |
303 | | |
304 | | /* BUILTIN\Administrators get everything -- *always* */ |
305 | |
|
306 | 0 | if ( lp_enable_privileges() ) { |
307 | 0 | if ( !grant_all_privileges( &global_sid_Builtin_Administrators ) ) { |
308 | 0 | DEBUG(1,("init_account_policy: Failed to grant privileges " |
309 | 0 | "to BUILTIN\\Administrators!\n")); |
310 | 0 | } |
311 | 0 | } |
312 | |
|
313 | 0 | if (dbwrap_transaction_commit(db) != 0) { |
314 | 0 | DEBUG(0, ("transaction_commit failed\n")); |
315 | 0 | TALLOC_FREE(db); |
316 | 0 | return false; |
317 | 0 | } |
318 | | |
319 | 0 | return True; |
320 | | |
321 | 0 | cancel: |
322 | 0 | if (dbwrap_transaction_cancel(db)) { |
323 | 0 | smb_panic("transaction_cancel failed"); |
324 | 0 | } |
325 | 0 | TALLOC_FREE(db); |
326 | |
|
327 | 0 | return false; |
328 | 0 | } |
329 | | |
330 | | /***************************************************************************** |
331 | | Get an account policy (from tdb) |
332 | | *****************************************************************************/ |
333 | | |
334 | | bool account_policy_get(enum pdb_policy_type type, uint32_t *value) |
335 | 0 | { |
336 | 0 | const char *name; |
337 | 0 | uint32_t regval; |
338 | 0 | NTSTATUS status; |
339 | |
|
340 | 0 | if (!init_account_policy()) { |
341 | 0 | return False; |
342 | 0 | } |
343 | | |
344 | 0 | if (value) { |
345 | 0 | *value = 0; |
346 | 0 | } |
347 | |
|
348 | 0 | name = decode_account_policy_name(type); |
349 | 0 | if (name == NULL) { |
350 | 0 | DEBUG(1, ("account_policy_get: Field %d is not a valid account policy type! Cannot get, returning 0.\n", type)); |
351 | 0 | return False; |
352 | 0 | } |
353 | | |
354 | 0 | status = dbwrap_fetch_uint32_bystring(db, name, ®val); |
355 | 0 | if (!NT_STATUS_IS_OK(status)) { |
356 | 0 | DEBUG(2, ("account_policy_get: tdb_fetch_uint32_t failed for type %d (%s), returning 0\n", type, name)); |
357 | 0 | return False; |
358 | 0 | } |
359 | | |
360 | 0 | if (value) { |
361 | 0 | *value = regval; |
362 | 0 | } |
363 | |
|
364 | 0 | DEBUG(10,("account_policy_get: name: %s, val: %d\n", name, regval)); |
365 | 0 | return True; |
366 | 0 | } |
367 | | |
368 | | |
369 | | /**************************************************************************** |
370 | | Set an account policy (in tdb) |
371 | | ****************************************************************************/ |
372 | | |
373 | | bool account_policy_set(enum pdb_policy_type type, uint32_t value) |
374 | 0 | { |
375 | 0 | const char *name; |
376 | 0 | NTSTATUS status; |
377 | |
|
378 | 0 | if (!init_account_policy()) { |
379 | 0 | return False; |
380 | 0 | } |
381 | | |
382 | 0 | name = decode_account_policy_name(type); |
383 | 0 | if (name == NULL) { |
384 | 0 | DEBUG(1, ("Field %d is not a valid account policy type! Cannot set.\n", type)); |
385 | 0 | return False; |
386 | 0 | } |
387 | | |
388 | 0 | status = dbwrap_trans_store_uint32_bystring(db, name, value); |
389 | 0 | if (!NT_STATUS_IS_OK(status)) { |
390 | 0 | DEBUG(1, ("store_uint32_t failed for type %d (%s) on value " |
391 | 0 | "%u: %s\n", type, name, value, nt_errstr(status))); |
392 | 0 | return False; |
393 | 0 | } |
394 | | |
395 | 0 | DEBUG(10,("account_policy_set: name: %s, value: %d\n", name, value)); |
396 | |
|
397 | 0 | return True; |
398 | 0 | } |
399 | | |
400 | | /**************************************************************************** |
401 | | Set an account policy in the cache |
402 | | ****************************************************************************/ |
403 | | |
404 | | bool cache_account_policy_set(enum pdb_policy_type type, uint32_t value) |
405 | 0 | { |
406 | 0 | const char *policy_name = NULL; |
407 | 0 | char *cache_key = NULL; |
408 | 0 | char *cache_value = NULL; |
409 | 0 | bool ret = False; |
410 | |
|
411 | 0 | policy_name = decode_account_policy_name(type); |
412 | 0 | if (policy_name == NULL) { |
413 | 0 | DEBUG(0,("cache_account_policy_set: no policy found\n")); |
414 | 0 | return False; |
415 | 0 | } |
416 | | |
417 | 0 | if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) { |
418 | 0 | DEBUG(0, ("asprintf failed\n")); |
419 | 0 | goto done; |
420 | 0 | } |
421 | | |
422 | 0 | if (asprintf(&cache_value, "%lu\n", (unsigned long)value) < 0) { |
423 | 0 | DEBUG(0, ("asprintf failed\n")); |
424 | 0 | goto done; |
425 | 0 | } |
426 | | |
427 | 0 | DEBUG(10,("cache_account_policy_set: updating account pol cache\n")); |
428 | |
|
429 | 0 | ret = gencache_set(cache_key, cache_value, time(NULL)+AP_TTL); |
430 | |
|
431 | 0 | done: |
432 | 0 | SAFE_FREE(cache_key); |
433 | 0 | SAFE_FREE(cache_value); |
434 | 0 | return ret; |
435 | 0 | } |
436 | | |
437 | | /***************************************************************************** |
438 | | Get an account policy from the cache |
439 | | *****************************************************************************/ |
440 | | |
441 | | bool cache_account_policy_get(enum pdb_policy_type type, uint32_t *value) |
442 | 0 | { |
443 | 0 | const char *policy_name = NULL; |
444 | 0 | char *cache_key = NULL; |
445 | 0 | char *cache_value = NULL; |
446 | 0 | bool ret = False; |
447 | |
|
448 | 0 | policy_name = decode_account_policy_name(type); |
449 | 0 | if (policy_name == NULL) { |
450 | 0 | DEBUG(0,("cache_account_policy_set: no policy found\n")); |
451 | 0 | return False; |
452 | 0 | } |
453 | | |
454 | 0 | if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) { |
455 | 0 | DEBUG(0, ("asprintf failed\n")); |
456 | 0 | goto done; |
457 | 0 | } |
458 | | |
459 | 0 | if (gencache_get(cache_key, talloc_tos(), &cache_value, NULL)) { |
460 | 0 | int error = 0; |
461 | 0 | uint32_t tmp; |
462 | |
|
463 | 0 | tmp = smb_strtoul(cache_value, |
464 | 0 | NULL, |
465 | 0 | 10, |
466 | 0 | &error, |
467 | 0 | SMB_STR_STANDARD); |
468 | 0 | if (error != 0) { |
469 | 0 | goto done; |
470 | 0 | } |
471 | 0 | *value = tmp; |
472 | 0 | ret = True; |
473 | 0 | } |
474 | | |
475 | 0 | done: |
476 | 0 | SAFE_FREE(cache_key); |
477 | 0 | TALLOC_FREE(cache_value); |
478 | 0 | return ret; |
479 | 0 | } |
480 | | |
481 | | /**************************************************************************** |
482 | | ****************************************************************************/ |
483 | | |
484 | | struct db_context *get_account_pol_db( void ) |
485 | 0 | { |
486 | |
|
487 | 0 | if ( db == NULL ) { |
488 | 0 | if ( !init_account_policy() ) { |
489 | 0 | return NULL; |
490 | 0 | } |
491 | 0 | } |
492 | | |
493 | 0 | return db; |
494 | 0 | } |