Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * RPC Pipe client / server routines
4 : * Copyright (C) Andrew Tridgell 1992-2006,
5 : * Copyright (C) Jean François Micouleau 1998-2001.
6 : * Copyright (C) Volker Lendecke 2006.
7 : * Copyright (C) Gerald Carter 2006.
8 : *
9 : * This program is free software; you can redistribute it and/or modify
10 : * it under the terms of the GNU General Public License as published by
11 : * the Free Software Foundation; either version 3 of the License, or
12 : * (at your option) any later version.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "passdb.h"
26 : #include "groupdb/mapping.h"
27 : #include "dbwrap/dbwrap.h"
28 : #include "dbwrap/dbwrap_open.h"
29 : #include "util_tdb.h"
30 : #include "../libcli/security/security.h"
31 : #include "groupdb/mapping_tdb.h"
32 : #include "lib/util/smb_strtox.h"
33 :
34 : static struct db_context *db; /* used for driver files */
35 :
36 : static bool enum_group_mapping(const struct dom_sid *domsid,
37 : enum lsa_SidType sid_name_use,
38 : GROUP_MAP ***pp_rmap,
39 : size_t *p_num_entries,
40 : bool unix_only);
41 : static bool group_map_remove(const struct dom_sid *sid);
42 :
43 : static bool mapping_switch(const char *ldb_path);
44 :
45 : /****************************************************************************
46 : Open the group mapping tdb.
47 : ****************************************************************************/
48 1526 : static bool init_group_mapping(void)
49 : {
50 5 : char *tdb_path;
51 5 : char *ldb_path;
52 :
53 1526 : if (db != NULL) {
54 0 : return true;
55 : }
56 :
57 1526 : tdb_path = state_path(talloc_tos(), "group_mapping.tdb");
58 1526 : if (tdb_path == NULL) {
59 0 : return false;
60 : }
61 1526 : db = db_open(NULL, tdb_path, 0,
62 : TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
63 : DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
64 1526 : if (db == NULL) {
65 0 : DEBUG(0, ("Failed to open group mapping database: %s\n",
66 : strerror(errno)));
67 0 : talloc_free(tdb_path);
68 0 : return false;
69 : }
70 :
71 1526 : ldb_path = state_path(talloc_tos(), "group_mapping.ldb");
72 1526 : if (ldb_path == NULL) {
73 0 : talloc_free(tdb_path);
74 0 : return false;
75 : }
76 1526 : if (file_exist(ldb_path) && !mapping_switch(ldb_path)) {
77 0 : unlink(tdb_path);
78 0 : talloc_free(tdb_path);
79 0 : talloc_free(ldb_path);
80 0 : return false;
81 :
82 : } else {
83 : /* handle upgrade from old versions of the database */
84 : #if 0 /* -- Needs conversion to dbwrap -- */
85 : const char *vstring = "INFO/version";
86 : int32 vers_id;
87 : GROUP_MAP *map_table = NULL;
88 : size_t num_entries = 0;
89 :
90 : /* handle a Samba upgrade */
91 : tdb_lock_bystring(tdb, vstring);
92 :
93 : /* Cope with byte-reversed older versions of the db. */
94 : vers_id = tdb_fetch_int32(tdb, vstring);
95 : if ((vers_id == DATABASE_VERSION_V1)
96 : || (IREV(vers_id) == DATABASE_VERSION_V1)) {
97 : /*
98 : * Written on a bigendian machine with old fetch_int
99 : * code. Save as le.
100 : */
101 : tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
102 : vers_id = DATABASE_VERSION_V2;
103 : }
104 :
105 : /* if its an unknown version we remove everything in the db */
106 :
107 : if (vers_id != DATABASE_VERSION_V2) {
108 : tdb_wipe_all(tdb);
109 : tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
110 : }
111 :
112 : tdb_unlock_bystring(tdb, vstring);
113 :
114 : /* cleanup any map entries with a gid == -1 */
115 :
116 : if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
117 : &num_entries, False ) ) {
118 : int i;
119 :
120 : for ( i=0; i<num_entries; i++ ) {
121 : if ( map_table[i].gid == -1 ) {
122 : group_map_remove( &map_table[i].sid );
123 : }
124 : }
125 :
126 : SAFE_FREE( map_table );
127 : }
128 : #endif
129 5 : }
130 1526 : talloc_free(tdb_path);
131 1526 : talloc_free(ldb_path);
132 1526 : return true;
133 : }
134 :
135 104048 : static char *group_mapping_key(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
136 : {
137 37 : struct dom_sid_buf sidstr;
138 :
139 104048 : return talloc_asprintf(
140 : mem_ctx, "%s%s", GROUP_PREFIX, dom_sid_str_buf(sid, &sidstr));
141 : }
142 :
143 : /****************************************************************************
144 : ****************************************************************************/
145 800 : static bool add_mapping_entry(GROUP_MAP *map, int flag)
146 : {
147 0 : char *key, *buf;
148 0 : int len;
149 0 : NTSTATUS status;
150 :
151 800 : key = group_mapping_key(talloc_tos(), &map->sid);
152 800 : if (key == NULL) {
153 0 : return false;
154 : }
155 :
156 1600 : len = tdb_pack(NULL, 0, "ddff",
157 800 : map->gid, map->sid_name_use, map->nt_name, map->comment);
158 :
159 800 : buf = talloc_array(key, char, len);
160 800 : if (!buf) {
161 0 : TALLOC_FREE(key);
162 0 : return false;
163 : }
164 1600 : len = tdb_pack((uint8_t *)buf, len, "ddff", map->gid,
165 800 : map->sid_name_use, map->nt_name, map->comment);
166 :
167 800 : status = dbwrap_trans_store(
168 : db, string_term_tdb_data(key),
169 : make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
170 :
171 800 : TALLOC_FREE(key);
172 :
173 800 : return NT_STATUS_IS_OK(status);
174 : }
175 :
176 :
177 : /****************************************************************************
178 : Return the sid and the type of the unix group.
179 : ****************************************************************************/
180 :
181 103230 : static bool get_group_map_from_sid(struct dom_sid sid, GROUP_MAP *map)
182 : {
183 37 : TDB_DATA dbuf;
184 37 : char *key;
185 103230 : int ret = 0;
186 37 : NTSTATUS status;
187 37 : fstring nt_name;
188 37 : fstring comment;
189 :
190 : /* the key is the SID, retrieving is direct */
191 :
192 103230 : key = group_mapping_key(talloc_tos(), &sid);
193 103230 : if (key == NULL) {
194 0 : return false;
195 : }
196 :
197 103230 : status = dbwrap_fetch_bystring(db, key, key, &dbuf);
198 103230 : if (!NT_STATUS_IS_OK(status)) {
199 70889 : TALLOC_FREE(key);
200 70889 : return false;
201 : }
202 :
203 32341 : ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
204 : &map->gid, &map->sid_name_use,
205 : &nt_name, &comment);
206 :
207 32341 : TALLOC_FREE(key);
208 :
209 32341 : if ( ret == -1 ) {
210 0 : DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
211 0 : return false;
212 : }
213 :
214 32341 : sid_copy(&map->sid, &sid);
215 :
216 32341 : map->nt_name = talloc_strdup(map, nt_name);
217 32341 : if (!map->nt_name) {
218 0 : return false;
219 : }
220 32341 : map->comment = talloc_strdup(map, comment);
221 32341 : if (!map->comment) {
222 0 : return false;
223 : }
224 :
225 32308 : return true;
226 : }
227 :
228 3417728 : static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
229 : {
230 3417728 : TDB_DATA key = dbwrap_record_get_key(rec);
231 3417728 : TDB_DATA value = dbwrap_record_get_value(rec);
232 3417728 : int ret = 0;
233 182 : fstring nt_name;
234 182 : fstring comment;
235 :
236 3417728 : if ((key.dsize < strlen(GROUP_PREFIX))
237 3417728 : || (strncmp((char *)key.dptr, GROUP_PREFIX,
238 : GROUP_PREFIX_LEN) != 0)) {
239 94173 : return False;
240 : }
241 :
242 3323542 : if (!string_to_sid(&map->sid, (const char *)key.dptr
243 : + GROUP_PREFIX_LEN)) {
244 0 : return False;
245 : }
246 :
247 3323542 : ret = tdb_unpack(value.dptr, value.dsize, "ddff",
248 : &map->gid, &map->sid_name_use,
249 : &nt_name, &comment);
250 :
251 3323542 : if (ret == -1) {
252 0 : DEBUG(3, ("dbrec2map: tdb_unpack failure\n"));
253 0 : return false;
254 : }
255 :
256 3323542 : map->nt_name = talloc_strdup(map, nt_name);
257 3323542 : if (!map->nt_name) {
258 0 : return false;
259 : }
260 3323542 : map->comment = talloc_strdup(map, comment);
261 3323542 : if (!map->comment) {
262 0 : return false;
263 : }
264 :
265 3323373 : return true;
266 : }
267 :
268 : struct find_map_state {
269 : bool found;
270 : const char *name; /* If != NULL, look for name */
271 : gid_t gid; /* valid iff name == NULL */
272 : GROUP_MAP *map;
273 : };
274 :
275 3414402 : static int find_map(struct db_record *rec, void *private_data)
276 : {
277 3414402 : struct find_map_state *state = (struct find_map_state *)private_data;
278 :
279 3414402 : if (!dbrec2map(rec, state->map)) {
280 94096 : DEBUG(10, ("failed to unpack map\n"));
281 94096 : return 0;
282 : }
283 :
284 3320306 : if (state->name != NULL) {
285 222804 : if (strequal(state->name, state->map->nt_name)) {
286 64 : state->found = true;
287 64 : return 1;
288 : }
289 : }
290 : else {
291 3097502 : if (state->map->gid == state->gid) {
292 14 : state->found = true;
293 14 : return 1;
294 : }
295 : }
296 :
297 3320163 : return 0;
298 : }
299 :
300 : /****************************************************************************
301 : Return the sid and the type of the unix group.
302 : ****************************************************************************/
303 :
304 220335 : static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
305 : {
306 5 : struct find_map_state state;
307 :
308 220335 : state.found = false;
309 220335 : state.name = NULL; /* Indicate we're looking for gid */
310 220335 : state.gid = gid;
311 220335 : state.map = map;
312 :
313 220335 : dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
314 :
315 220335 : return state.found;
316 : }
317 :
318 : /****************************************************************************
319 : Return the sid and the type of the unix group.
320 : ****************************************************************************/
321 :
322 2156 : static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
323 : {
324 0 : struct find_map_state state;
325 :
326 2156 : state.found = false;
327 2156 : state.name = name;
328 2156 : state.map = map;
329 :
330 2156 : dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
331 :
332 2156 : return state.found;
333 : }
334 :
335 : /****************************************************************************
336 : Remove a group mapping entry.
337 : ****************************************************************************/
338 :
339 18 : static bool group_map_remove(const struct dom_sid *sid)
340 : {
341 0 : char *key;
342 0 : NTSTATUS status;
343 :
344 18 : key = group_mapping_key(talloc_tos(), sid);
345 18 : if (key == NULL) {
346 0 : return false;
347 : }
348 :
349 18 : status = dbwrap_trans_delete(db, string_term_tdb_data(key));
350 :
351 18 : TALLOC_FREE(key);
352 18 : return NT_STATUS_IS_OK(status);
353 : }
354 :
355 : /****************************************************************************
356 : Enumerate the group mapping.
357 : ****************************************************************************/
358 :
359 : struct enum_map_state {
360 : const struct dom_sid *domsid;
361 : enum lsa_SidType sid_name_use;
362 : bool unix_only;
363 :
364 : size_t num_maps;
365 : GROUP_MAP **maps;
366 : };
367 :
368 3326 : static int collect_map(struct db_record *rec, void *private_data)
369 : {
370 3326 : struct enum_map_state *state = (struct enum_map_state *)private_data;
371 112 : GROUP_MAP *map;
372 112 : GROUP_MAP **tmp;
373 :
374 3326 : map = talloc_zero(NULL, GROUP_MAP);
375 3326 : if (!map) {
376 0 : DEBUG(0, ("Unable to allocate group map!\n"));
377 0 : return 1;
378 : }
379 :
380 3326 : if (!dbrec2map(rec, map)) {
381 90 : TALLOC_FREE(map);
382 90 : return 0;
383 : }
384 : /* list only the type or everything if UNKNOWN */
385 3236 : if (state->sid_name_use != SID_NAME_UNKNOWN
386 3158 : && state->sid_name_use != map->sid_name_use) {
387 1296 : DEBUG(11,("enum_group_mapping: group %s is not of the "
388 : "requested type\n", map->nt_name));
389 1296 : TALLOC_FREE(map);
390 1296 : return 0;
391 : }
392 :
393 1940 : if ((state->unix_only == ENUM_ONLY_MAPPED) && (map->gid == -1)) {
394 0 : DEBUG(11,("enum_group_mapping: group %s is non mapped\n",
395 : map->nt_name));
396 0 : TALLOC_FREE(map);
397 0 : return 0;
398 : }
399 :
400 3800 : if ((state->domsid != NULL) &&
401 1860 : (dom_sid_compare_domain(state->domsid, &map->sid) != 0)) {
402 0 : struct dom_sid_buf buf;
403 624 : DEBUG(11,("enum_group_mapping: group %s is not in domain\n",
404 : dom_sid_str_buf(&map->sid, &buf)));
405 624 : TALLOC_FREE(map);
406 624 : return 0;
407 : }
408 :
409 1316 : tmp = talloc_realloc(NULL, state->maps, GROUP_MAP *,
410 : state->num_maps + 1);
411 1316 : if (!tmp) {
412 0 : DEBUG(0,("enum_group_mapping: Unable to enlarge group "
413 : "map!\n"));
414 0 : TALLOC_FREE(map);
415 0 : return 1;
416 : }
417 :
418 1316 : state->maps = tmp;
419 1316 : state->maps[state->num_maps] = talloc_move(state->maps, &map);
420 1316 : state->num_maps++;
421 1316 : return 0;
422 : }
423 :
424 30 : static bool enum_group_mapping(const struct dom_sid *domsid,
425 : enum lsa_SidType sid_name_use,
426 : GROUP_MAP ***pp_rmap,
427 : size_t *p_num_entries, bool unix_only)
428 : {
429 8 : struct enum_map_state state;
430 8 : NTSTATUS status;
431 :
432 30 : state.domsid = domsid;
433 30 : state.sid_name_use = sid_name_use;
434 30 : state.unix_only = unix_only;
435 30 : state.num_maps = 0;
436 30 : state.maps = NULL;
437 :
438 30 : status = dbwrap_traverse_read(db, collect_map, (void *)&state, NULL);
439 30 : if (!NT_STATUS_IS_OK(status)) {
440 0 : TALLOC_FREE(state.maps);
441 0 : return false;
442 : }
443 :
444 30 : *pp_rmap = state.maps;
445 30 : *p_num_entries = state.num_maps;
446 :
447 30 : return true;
448 : }
449 :
450 : /* This operation happens on session setup, so it should better be fast. We
451 : * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
452 :
453 318244 : static NTSTATUS one_alias_membership(const struct dom_sid *member,
454 : struct dom_sid **sids, size_t *num)
455 : {
456 0 : struct dom_sid_buf tmp;
457 0 : fstring key;
458 0 : char *string_sid;
459 0 : TDB_DATA dbuf;
460 0 : const char *p;
461 0 : NTSTATUS status;
462 318244 : TALLOC_CTX *frame = talloc_stackframe();
463 :
464 318244 : slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
465 : dom_sid_str_buf(member, &tmp));
466 :
467 318244 : status = dbwrap_fetch_bystring(db, frame, key, &dbuf);
468 318244 : if (!NT_STATUS_IS_OK(status)) {
469 304655 : TALLOC_FREE(frame);
470 304655 : return NT_STATUS_OK;
471 : }
472 :
473 13589 : p = (const char *)dbuf.dptr;
474 :
475 27178 : while (next_token_talloc(frame, &p, &string_sid, " ")) {
476 0 : struct dom_sid alias;
477 0 : uint32_t num_sids;
478 :
479 13589 : if (!string_to_sid(&alias, string_sid))
480 0 : continue;
481 :
482 13589 : num_sids = *num;
483 13589 : status= add_sid_to_array_unique(NULL, &alias, sids, &num_sids);
484 13589 : if (!NT_STATUS_IS_OK(status)) {
485 0 : goto done;
486 : }
487 13589 : *num = num_sids;
488 : }
489 :
490 13589 : done:
491 13589 : TALLOC_FREE(frame);
492 13589 : return status;
493 : }
494 :
495 94 : static NTSTATUS alias_memberships(const struct dom_sid *members, size_t num_members,
496 : struct dom_sid **sids, size_t *num)
497 : {
498 0 : size_t i;
499 :
500 94 : *num = 0;
501 94 : *sids = NULL;
502 :
503 188 : for (i=0; i<num_members; i++) {
504 94 : NTSTATUS status = one_alias_membership(&members[i], sids, num);
505 94 : if (!NT_STATUS_IS_OK(status))
506 0 : return status;
507 : }
508 94 : return NT_STATUS_OK;
509 : }
510 :
511 74 : static bool is_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
512 : {
513 0 : struct dom_sid *sids;
514 0 : size_t i;
515 0 : size_t num;
516 :
517 : /* This feels the wrong way round, but the on-disk data structure
518 : * dictates it this way. */
519 74 : if (!NT_STATUS_IS_OK(alias_memberships(member, 1, &sids, &num)))
520 0 : return False;
521 :
522 74 : for (i=0; i<num; i++) {
523 15 : if (dom_sid_compare(alias, &sids[i]) == 0) {
524 15 : TALLOC_FREE(sids);
525 15 : return True;
526 : }
527 : }
528 59 : TALLOC_FREE(sids);
529 59 : return False;
530 : }
531 :
532 :
533 74 : static NTSTATUS add_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
534 : {
535 0 : GROUP_MAP *map;
536 0 : char *key;
537 0 : struct dom_sid_buf string_sid;
538 0 : char *new_memberstring;
539 0 : struct db_record *rec;
540 0 : NTSTATUS status;
541 0 : TDB_DATA value;
542 :
543 74 : map = talloc_zero(talloc_tos(), GROUP_MAP);
544 74 : if (!map) {
545 0 : return NT_STATUS_NO_MEMORY;
546 : }
547 :
548 74 : if (!get_group_map_from_sid(*alias, map)) {
549 0 : TALLOC_FREE(map);
550 0 : return NT_STATUS_NO_SUCH_ALIAS;
551 : }
552 :
553 74 : if ((map->sid_name_use != SID_NAME_ALIAS) &&
554 2 : (map->sid_name_use != SID_NAME_WKN_GRP)) {
555 0 : TALLOC_FREE(map);
556 0 : return NT_STATUS_NO_SUCH_ALIAS;
557 : }
558 :
559 74 : TALLOC_FREE(map);
560 :
561 74 : if (is_aliasmem(alias, member))
562 15 : return NT_STATUS_MEMBER_IN_ALIAS;
563 :
564 59 : key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
565 : dom_sid_str_buf(member, &string_sid));
566 59 : if (key == NULL) {
567 0 : return NT_STATUS_NO_MEMORY;
568 : }
569 :
570 59 : if (dbwrap_transaction_start(db) != 0) {
571 0 : DEBUG(0, ("transaction_start failed\n"));
572 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
573 : }
574 :
575 59 : rec = dbwrap_fetch_locked(db, key, string_term_tdb_data(key));
576 :
577 59 : if (rec == NULL) {
578 0 : DEBUG(10, ("fetch_lock failed\n"));
579 0 : TALLOC_FREE(key);
580 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
581 0 : goto cancel;
582 : }
583 :
584 59 : value = dbwrap_record_get_value(rec);
585 :
586 59 : dom_sid_str_buf(alias, &string_sid);
587 :
588 59 : if (value.dptr != NULL) {
589 0 : new_memberstring = talloc_asprintf(
590 0 : key, "%s %s", (char *)(value.dptr), string_sid.buf);
591 : } else {
592 59 : new_memberstring = talloc_strdup(key, string_sid.buf);
593 : }
594 :
595 59 : if (new_memberstring == NULL) {
596 0 : TALLOC_FREE(key);
597 0 : status = NT_STATUS_NO_MEMORY;
598 0 : goto cancel;
599 : }
600 :
601 59 : status = dbwrap_record_store(rec, string_term_tdb_data(new_memberstring), 0);
602 :
603 59 : TALLOC_FREE(key);
604 :
605 59 : if (!NT_STATUS_IS_OK(status)) {
606 0 : DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
607 0 : goto cancel;
608 : }
609 :
610 59 : if (dbwrap_transaction_commit(db) != 0) {
611 0 : DEBUG(0, ("transaction_commit failed\n"));
612 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
613 0 : return status;
614 : }
615 :
616 59 : return NT_STATUS_OK;
617 :
618 0 : cancel:
619 0 : if (dbwrap_transaction_cancel(db) != 0) {
620 0 : smb_panic("transaction_cancel failed");
621 : }
622 :
623 0 : return status;
624 : }
625 :
626 : struct aliasmem_state {
627 : TALLOC_CTX *mem_ctx;
628 : const struct dom_sid *alias;
629 : struct dom_sid **sids;
630 : size_t *num;
631 : };
632 :
633 520 : static int collect_aliasmem(struct db_record *rec, void *priv)
634 : {
635 520 : struct aliasmem_state *state = (struct aliasmem_state *)priv;
636 420 : const char *p;
637 420 : char *alias_string;
638 420 : TALLOC_CTX *frame;
639 520 : TDB_DATA key = dbwrap_record_get_key(rec);
640 520 : TDB_DATA value = dbwrap_record_get_value(rec);
641 :
642 520 : if (strncmp((const char *)key.dptr, MEMBEROF_PREFIX,
643 : MEMBEROF_PREFIX_LEN) != 0)
644 52 : return 0;
645 :
646 48 : p = (const char *)value.dptr;
647 :
648 48 : frame = talloc_stackframe();
649 :
650 96 : while (next_token_talloc(frame, &p, &alias_string, " ")) {
651 0 : struct dom_sid alias, member;
652 0 : const char *member_string;
653 0 : uint32_t num_sids;
654 :
655 48 : if (!string_to_sid(&alias, alias_string))
656 22 : continue;
657 :
658 48 : if (dom_sid_compare(state->alias, &alias) != 0)
659 22 : continue;
660 :
661 : /* Ok, we found the alias we're looking for in the membership
662 : * list currently scanned. The key represents the alias
663 : * member. Add that. */
664 :
665 26 : member_string = strchr((const char *)key.dptr, '/');
666 :
667 : /* Above we tested for MEMBEROF_PREFIX which includes the
668 : * slash. */
669 :
670 26 : SMB_ASSERT(member_string != NULL);
671 26 : member_string += 1;
672 :
673 26 : if (!string_to_sid(&member, member_string))
674 0 : continue;
675 :
676 26 : num_sids = *state->num;
677 26 : if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx, &member,
678 : state->sids,
679 : &num_sids)))
680 : {
681 : /* talloc fail. */
682 0 : break;
683 : }
684 26 : *state->num = num_sids;
685 : }
686 :
687 48 : TALLOC_FREE(frame);
688 48 : return 0;
689 : }
690 :
691 38 : static NTSTATUS enum_aliasmem(const struct dom_sid *alias, TALLOC_CTX *mem_ctx,
692 : struct dom_sid **sids, size_t *num)
693 : {
694 30 : GROUP_MAP *map;
695 30 : struct aliasmem_state state;
696 :
697 38 : map = talloc_zero(talloc_tos(), GROUP_MAP);
698 38 : if (!map) {
699 0 : return NT_STATUS_NO_MEMORY;
700 : }
701 :
702 38 : if (!get_group_map_from_sid(*alias, map)) {
703 0 : TALLOC_FREE(map);
704 0 : return NT_STATUS_NO_SUCH_ALIAS;
705 : }
706 :
707 38 : if ((map->sid_name_use != SID_NAME_ALIAS) &&
708 0 : (map->sid_name_use != SID_NAME_WKN_GRP)) {
709 0 : TALLOC_FREE(map);
710 0 : return NT_STATUS_NO_SUCH_ALIAS;
711 : }
712 :
713 38 : TALLOC_FREE(map);
714 :
715 38 : *sids = NULL;
716 38 : *num = 0;
717 :
718 38 : state.alias = alias;
719 38 : state.sids = sids;
720 38 : state.num = num;
721 38 : state.mem_ctx = mem_ctx;
722 :
723 38 : dbwrap_traverse_read(db, collect_aliasmem, &state, NULL);
724 38 : return NT_STATUS_OK;
725 : }
726 :
727 20 : static NTSTATUS del_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
728 : {
729 0 : NTSTATUS status;
730 0 : struct dom_sid *sids;
731 0 : size_t i, num;
732 20 : bool found = False;
733 0 : char *member_string;
734 0 : char *key;
735 0 : struct dom_sid_buf sid_string;
736 :
737 20 : if (dbwrap_transaction_start(db) != 0) {
738 0 : DEBUG(0, ("transaction_start failed\n"));
739 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
740 : }
741 :
742 20 : status = alias_memberships(member, 1, &sids, &num);
743 :
744 20 : if (!NT_STATUS_IS_OK(status)) {
745 0 : goto cancel;
746 : }
747 :
748 20 : for (i=0; i<num; i++) {
749 20 : if (dom_sid_compare(&sids[i], alias) == 0) {
750 20 : found = True;
751 20 : break;
752 : }
753 : }
754 :
755 20 : if (!found) {
756 0 : TALLOC_FREE(sids);
757 0 : status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
758 0 : goto cancel;
759 : }
760 :
761 20 : if (i < num)
762 20 : sids[i] = sids[num-1];
763 :
764 20 : num -= 1;
765 :
766 20 : key = talloc_asprintf(
767 : sids,
768 : "%s%s",
769 : MEMBEROF_PREFIX,
770 : dom_sid_str_buf(member, &sid_string));
771 20 : if (key == NULL) {
772 0 : TALLOC_FREE(sids);
773 0 : status = NT_STATUS_NO_MEMORY;
774 0 : goto cancel;
775 : }
776 :
777 20 : if (num == 0) {
778 20 : status = dbwrap_delete_bystring(db, key);
779 20 : goto commit;
780 : }
781 :
782 0 : member_string = talloc_strdup(sids, "");
783 0 : if (member_string == NULL) {
784 0 : TALLOC_FREE(sids);
785 0 : status = NT_STATUS_NO_MEMORY;
786 0 : goto cancel;
787 : }
788 :
789 0 : for (i=0; i<num; i++) {
790 :
791 0 : member_string = talloc_asprintf_append_buffer(
792 : member_string,
793 : " %s",
794 0 : dom_sid_str_buf(&sids[i], &sid_string));
795 :
796 0 : if (member_string == NULL) {
797 0 : TALLOC_FREE(sids);
798 0 : status = NT_STATUS_NO_MEMORY;
799 0 : goto cancel;
800 : }
801 : }
802 :
803 0 : status = dbwrap_store_bystring(
804 : db, key, string_term_tdb_data(member_string), 0);
805 20 : commit:
806 20 : TALLOC_FREE(sids);
807 :
808 20 : if (!NT_STATUS_IS_OK(status)) {
809 0 : DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
810 : nt_errstr(status)));
811 0 : goto cancel;
812 : }
813 :
814 20 : if (dbwrap_transaction_commit(db) != 0) {
815 0 : DEBUG(0, ("transaction_commit failed\n"));
816 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
817 0 : return status;
818 : }
819 :
820 20 : return NT_STATUS_OK;
821 :
822 0 : cancel:
823 0 : if (dbwrap_transaction_cancel(db) != 0) {
824 0 : smb_panic("transaction_cancel failed");
825 : }
826 0 : return status;
827 : }
828 :
829 :
830 : /* -- ldb->tdb switching code -------------------------------------------- */
831 :
832 : /* change this if the data format ever changes */
833 : #define LTDB_PACKING_FORMAT 0x26011967
834 :
835 : /* old packing formats (not supported for now,
836 : * it was never used for group mapping AFAIK) */
837 : #define LTDB_PACKING_FORMAT_NODN 0x26011966
838 :
839 0 : static unsigned int pull_uint32(uint8_t *p, int ofs)
840 : {
841 0 : p += ofs;
842 0 : return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
843 : }
844 :
845 : /*
846 : unpack a ldb message from a linear buffer in TDB_DATA
847 : */
848 0 : static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
849 : TDB_DATA data, void *ptr)
850 : {
851 0 : TALLOC_CTX *tmp_ctx = talloc_tos();
852 0 : GROUP_MAP *map = NULL;
853 0 : uint8_t *p;
854 0 : uint32_t format;
855 0 : uint32_t num_el;
856 0 : unsigned int remaining;
857 0 : unsigned int i, j;
858 0 : size_t len;
859 0 : char *name;
860 0 : char *val;
861 0 : uint32_t num_mem = 0;
862 0 : struct dom_sid *members = NULL;
863 0 : int error = 0;
864 :
865 0 : p = (uint8_t *)data.dptr;
866 0 : if (data.dsize < 8) {
867 0 : errno = EIO;
868 0 : goto failed;
869 : }
870 :
871 0 : format = pull_uint32(p, 0);
872 0 : num_el = pull_uint32(p, 4);
873 0 : p += 8;
874 :
875 0 : remaining = data.dsize - 8;
876 :
877 0 : switch (format) {
878 0 : case LTDB_PACKING_FORMAT:
879 0 : len = strnlen((char *)p, remaining);
880 0 : if (len == remaining) {
881 0 : errno = EIO;
882 0 : goto failed;
883 : }
884 :
885 0 : if (*p == '@') {
886 : /* ignore special LDB attributes */
887 0 : return 0;
888 : }
889 :
890 0 : if (strncmp((char *)p, "rid=", 4)) {
891 : /* unknown entry, ignore */
892 0 : DEBUG(3, ("Found unknown entry in group mapping "
893 : "database named [%s]\n", (char *)p));
894 0 : return 0;
895 : }
896 :
897 0 : remaining -= len + 1;
898 0 : p += len + 1;
899 0 : break;
900 :
901 0 : case LTDB_PACKING_FORMAT_NODN:
902 : default:
903 0 : errno = EIO;
904 0 : goto failed;
905 : }
906 :
907 0 : if (num_el == 0) {
908 : /* bad entry, ignore */
909 0 : return 0;
910 : }
911 :
912 0 : if (num_el > remaining / 6) {
913 0 : errno = EIO;
914 0 : goto failed;
915 : }
916 :
917 0 : map = talloc_zero(NULL, GROUP_MAP);
918 0 : if (!map) {
919 0 : errno = ENOMEM;
920 0 : goto failed;
921 : }
922 :
923 0 : for (i = 0; i < num_el; i++) {
924 0 : uint32_t num_vals;
925 :
926 0 : if (remaining < 10) {
927 0 : errno = EIO;
928 0 : goto failed;
929 : }
930 0 : len = strnlen((char *)p, remaining - 6);
931 0 : if (len == remaining - 6) {
932 0 : errno = EIO;
933 0 : goto failed;
934 : }
935 0 : name = talloc_strndup(tmp_ctx, (char *)p, len);
936 0 : if (name == NULL) {
937 0 : errno = ENOMEM;
938 0 : goto failed;
939 : }
940 0 : remaining -= len + 1;
941 0 : p += len + 1;
942 :
943 0 : num_vals = pull_uint32(p, 0);
944 0 : if (strcasecmp_m(name, "member") == 0) {
945 0 : num_mem = num_vals;
946 0 : members = talloc_array(tmp_ctx, struct dom_sid, num_mem);
947 0 : if (members == NULL) {
948 0 : errno = ENOMEM;
949 0 : goto failed;
950 : }
951 0 : } else if (num_vals != 1) {
952 0 : errno = EIO;
953 0 : goto failed;
954 : }
955 :
956 0 : p += 4;
957 0 : remaining -= 4;
958 :
959 0 : for (j = 0; j < num_vals; j++) {
960 0 : len = pull_uint32(p, 0);
961 0 : if (len > remaining-5) {
962 0 : errno = EIO;
963 0 : goto failed;
964 : }
965 :
966 0 : val = talloc_strndup(tmp_ctx, (char *)(p + 4), len);
967 0 : if (val == NULL) {
968 0 : errno = ENOMEM;
969 0 : goto failed;
970 : }
971 :
972 0 : remaining -= len+4+1;
973 0 : p += len+4+1;
974 :
975 : /* we ignore unknown or uninteresting attributes
976 : * (objectclass, etc.) */
977 0 : if (strcasecmp_m(name, "gidNumber") == 0) {
978 0 : map->gid = smb_strtoul(val,
979 : NULL,
980 : 10,
981 : &error,
982 : SMB_STR_FULL_STR_CONV);
983 0 : if (error != 0) {
984 0 : errno = EIO;
985 0 : goto failed;
986 : }
987 0 : } else if (strcasecmp_m(name, "sid") == 0) {
988 0 : if (!string_to_sid(&map->sid, val)) {
989 0 : errno = EIO;
990 0 : goto failed;
991 : }
992 0 : } else if (strcasecmp_m(name, "sidNameUse") == 0) {
993 0 : map->sid_name_use =
994 0 : smb_strtoul(val,
995 : NULL,
996 : 10,
997 : &error,
998 : SMB_STR_FULL_STR_CONV);
999 0 : if (error != 0) {
1000 0 : errno = EIO;
1001 0 : goto failed;
1002 : }
1003 0 : } else if (strcasecmp_m(name, "ntname") == 0) {
1004 0 : map->nt_name = talloc_strdup(map, val);
1005 0 : if (!map->nt_name) {
1006 0 : errno = ENOMEM;
1007 0 : goto failed;
1008 : }
1009 0 : } else if (strcasecmp_m(name, "comment") == 0) {
1010 0 : map->comment = talloc_strdup(map, val);
1011 0 : if (!map->comment) {
1012 0 : errno = ENOMEM;
1013 0 : goto failed;
1014 : }
1015 0 : } else if (strcasecmp_m(name, "member") == 0) {
1016 0 : if (!string_to_sid(&members[j], val)) {
1017 0 : errno = EIO;
1018 0 : goto failed;
1019 : }
1020 : }
1021 :
1022 0 : TALLOC_FREE(val);
1023 : }
1024 :
1025 0 : TALLOC_FREE(name);
1026 : }
1027 :
1028 0 : if (map->nt_name == NULL) {
1029 0 : errno = EIO;
1030 0 : goto failed;
1031 : }
1032 :
1033 0 : if (map->comment == NULL) {
1034 0 : map->comment = talloc_strdup(map, "");
1035 : }
1036 0 : if (map->comment == NULL) {
1037 0 : errno = ENOMEM;
1038 0 : goto failed;
1039 : }
1040 :
1041 0 : if (!add_mapping_entry(map, 0)) {
1042 0 : errno = EIO;
1043 0 : goto failed;
1044 : }
1045 :
1046 0 : if (num_mem) {
1047 0 : for (j = 0; j < num_mem; j++) {
1048 0 : NTSTATUS status;
1049 0 : status = add_aliasmem(&map->sid, &members[j]);
1050 0 : if (!NT_STATUS_IS_OK(status)) {
1051 0 : errno = EIO;
1052 0 : goto failed;
1053 : }
1054 : }
1055 : }
1056 :
1057 0 : if (remaining != 0) {
1058 0 : DEBUG(0, ("Error: %d bytes unread in ltdb_unpack_data\n",
1059 : remaining));
1060 : }
1061 :
1062 0 : TALLOC_FREE(map);
1063 0 : return 0;
1064 :
1065 0 : failed:
1066 0 : TALLOC_FREE(map);
1067 0 : return -1;
1068 : }
1069 :
1070 0 : static bool mapping_switch(const char *ldb_path)
1071 : {
1072 0 : TDB_CONTEXT *ltdb;
1073 0 : TALLOC_CTX *frame;
1074 0 : char *new_path;
1075 0 : int ret;
1076 :
1077 0 : frame = talloc_stackframe();
1078 :
1079 0 : ltdb = tdb_open_log(ldb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
1080 0 : if (ltdb == NULL) goto failed;
1081 :
1082 : /* ldb is just a very fancy tdb, read out raw data and perform
1083 : * conversion */
1084 0 : ret = tdb_traverse(ltdb, convert_ldb_record, NULL);
1085 0 : if (ret < 0) goto failed;
1086 :
1087 0 : if (ltdb) {
1088 0 : tdb_close(ltdb);
1089 0 : ltdb = NULL;
1090 : }
1091 :
1092 : /* now rename the old db out of the way */
1093 0 : new_path = state_path(talloc_tos(), "group_mapping.ldb.replaced");
1094 0 : if (!new_path) {
1095 0 : goto failed;
1096 : }
1097 0 : if (rename(ldb_path, new_path) != 0) {
1098 0 : DEBUG(0,("Failed to rename old group mapping database\n"));
1099 0 : goto failed;
1100 : }
1101 0 : TALLOC_FREE(frame);
1102 0 : return True;
1103 :
1104 0 : failed:
1105 0 : DEBUG(0, ("Failed to switch to tdb group mapping database\n"));
1106 0 : if (ltdb) tdb_close(ltdb);
1107 0 : TALLOC_FREE(frame);
1108 0 : return False;
1109 : }
1110 :
1111 : static const struct mapping_backend tdb_backend = {
1112 : .add_mapping_entry = add_mapping_entry,
1113 : .get_group_map_from_sid = get_group_map_from_sid,
1114 : .get_group_map_from_gid = get_group_map_from_gid,
1115 : .get_group_map_from_ntname = get_group_map_from_ntname,
1116 : .group_map_remove = group_map_remove,
1117 : .enum_group_mapping = enum_group_mapping,
1118 : .one_alias_membership = one_alias_membership,
1119 : .add_aliasmem = add_aliasmem,
1120 : .del_aliasmem = del_aliasmem,
1121 : .enum_aliasmem = enum_aliasmem
1122 : };
1123 :
1124 : /*
1125 : initialise the tdb mapping backend
1126 : */
1127 1526 : const struct mapping_backend *groupdb_tdb_init(void)
1128 : {
1129 1526 : if (!init_group_mapping()) {
1130 0 : DEBUG(0,("Failed to initialise tdb mapping backend\n"));
1131 0 : return NULL;
1132 : }
1133 :
1134 1521 : return &tdb_backend;
1135 : }
|