2 Unix SMB/CIFS implementation.
4 Winbind daemon - user related function
6 Copyright (C) Tim Potter 2000
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* High water mark keys */
27 #define HWM_GROUP "GROUP HWM"
28 #define HWM_USER "USER HWM"
30 /* idmap version determines auto-conversion */
31 #define IDMAP_VERSION 2
35 static TDB_CONTEXT
*idmap_tdb
;
37 /* Allocate either a user or group id from the pool */
39 static BOOL
allocate_id(uid_t
*id
, BOOL isgroup
)
43 /* Get current high water mark */
45 if ((hwm
= tdb_fetch_int32(idmap_tdb
,
46 isgroup
? HWM_GROUP
: HWM_USER
)) == -1) {
50 /* Return next available uid in list */
52 if ((isgroup
&& (hwm
> server_state
.gid_high
)) ||
53 (!isgroup
&& (hwm
> server_state
.uid_high
))) {
54 DEBUG(0, ("winbind %sid range full!\n", isgroup
? "g" : "u"));
64 /* Store new high water mark */
66 tdb_store_int32(idmap_tdb
, isgroup
? HWM_GROUP
: HWM_USER
, hwm
);
71 /* Get an id from a rid */
72 static BOOL
get_id_from_sid(DOM_SID
*sid
, uid_t
*id
, BOOL isgroup
)
78 /* Check if sid is present in database */
79 sid_to_string(keystr
, sid
);
82 key
.dsize
= strlen(keystr
) + 1;
84 data
= tdb_fetch(idmap_tdb
, key
);
90 /* Parse and return existing uid */
91 fstrcpy(scanstr
, isgroup
? "GID" : "UID");
92 fstrcat(scanstr
, " %d");
94 if (sscanf(data
.dptr
, scanstr
, &the_id
) == 1) {
103 SAFE_FREE(data
.dptr
);
106 /* Allocate a new id for this sid */
108 if (id
&& allocate_id(id
, isgroup
)) {
113 slprintf(keystr2
, sizeof(keystr2
), "%s %d", isgroup
? "GID" : "UID", *id
);
116 data
.dsize
= strlen(keystr2
) + 1;
118 tdb_store(idmap_tdb
, key
, data
, TDB_REPLACE
);
119 tdb_store(idmap_tdb
, data
, key
, TDB_REPLACE
);
128 /* Get a uid from a user sid */
129 BOOL
winbindd_idmap_get_uid_from_sid(DOM_SID
*sid
, uid_t
*uid
)
131 return get_id_from_sid(sid
, uid
, False
);
134 /* Get a gid from a group sid */
135 BOOL
winbindd_idmap_get_gid_from_sid(DOM_SID
*sid
, gid_t
*gid
)
137 return get_id_from_sid(sid
, gid
, True
);
140 /* Get a uid from a user rid */
141 BOOL
winbindd_idmap_get_uid_from_rid(const char *dom_name
, uint32 rid
, uid_t
*uid
)
143 struct winbindd_domain
*domain
;
146 if (!(domain
= find_domain_from_name(dom_name
))) {
150 sid_copy(&sid
, &domain
->sid
);
151 sid_append_rid(&sid
, rid
);
153 return get_id_from_sid(&sid
, uid
, False
);
156 /* Get a gid from a group rid */
157 BOOL
winbindd_idmap_get_gid_from_rid(const char *dom_name
, uint32 rid
, gid_t
*gid
)
159 struct winbindd_domain
*domain
;
162 if (!(domain
= find_domain_from_name(dom_name
))) {
166 sid_copy(&sid
, &domain
->sid
);
167 sid_append_rid(&sid
, rid
);
169 return get_id_from_sid(&sid
, gid
, True
);
173 BOOL
get_sid_from_id(int id
, DOM_SID
*sid
, BOOL isgroup
)
179 slprintf(keystr
, sizeof(keystr
), "%s %d", isgroup
? "GID" : "UID", id
);
182 key
.dsize
= strlen(keystr
) + 1;
184 data
= tdb_fetch(idmap_tdb
, key
);
187 result
= string_to_sid(sid
, data
.dptr
);
188 SAFE_FREE(data
.dptr
);
194 /* Get a sid from a uid */
195 BOOL
winbindd_idmap_get_sid_from_uid(uid_t uid
, DOM_SID
*sid
)
197 return get_sid_from_id((int)uid
, sid
, False
);
200 /* Get a sid from a gid */
201 BOOL
winbindd_idmap_get_sid_from_gid(gid_t gid
, DOM_SID
*sid
)
203 return get_sid_from_id((int)gid
, sid
, True
);
206 /* Get a user rid from a uid */
207 BOOL
winbindd_idmap_get_rid_from_uid(uid_t uid
, uint32
*user_rid
,
208 struct winbindd_domain
**domain
)
212 if (!get_sid_from_id((int)uid
, &sid
, False
)) {
216 *domain
= find_domain_from_sid(&sid
);
217 if (! *domain
) return False
;
219 sid_split_rid(&sid
, user_rid
);
224 /* Get a group rid from a gid */
226 BOOL
winbindd_idmap_get_rid_from_gid(gid_t gid
, uint32
*group_rid
,
227 struct winbindd_domain
**domain
)
231 if (!get_sid_from_id((int)gid
, &sid
, True
)) {
235 *domain
= find_domain_from_sid(&sid
);
236 if (! *domain
) return False
;
238 sid_split_rid(&sid
, group_rid
);
243 /* convert one record to the new format */
244 static int convert_fn(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA data
, void *ignored
)
246 struct winbindd_domain
*domain
;
254 p
= strchr(key
.dptr
, '/');
259 fstrcpy(dom_name
, key
.dptr
);
262 domain
= find_domain_from_name(dom_name
);
264 /* We must delete the old record. */
265 DEBUG(0,("winbindd: convert_fn : Unable to find domain %s\n", dom_name
));
266 DEBUG(0,("winbindd: convert_fn : deleting record %s\n", key
.dptr
));
267 tdb_delete(idmap_tdb
, key
);
273 sid_copy(&sid
, &domain
->sid
);
274 sid_append_rid(&sid
, rid
);
276 sid_to_string(keystr
, &sid
);
278 key2
.dsize
= strlen(keystr
) + 1;
280 if (tdb_store(idmap_tdb
, key2
, data
, TDB_INSERT
) != 0) {
282 DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", key2
.dptr
));
283 DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n"));
287 if (tdb_store(idmap_tdb
, data
, key2
, TDB_REPLACE
) != 0) {
289 DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", data
.dptr
));
290 DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n"));
294 tdb_delete(idmap_tdb
, key
);
300 /*****************************************************************************
301 Make a backup copy of the old idmap just to be safe.... JRA.
302 *****************************************************************************/
304 static BOOL
backup_old_idmap(const char *idmap_name
)
311 pstrcpy(new_name
, idmap_name
);
312 pstrcat(new_name
, ".bak");
314 DEBUG(10,("backup_old_idmap: backing up %s to %s before upgrade.\n",
315 idmap_name
, new_name
));
317 if (tdb_lockall(idmap_tdb
) == -1) {
318 DEBUG(10,("backup_old_idmap: failed to lock %s. Error %s\n",
319 idmap_name
, tdb_errorstr(idmap_tdb
) ));
322 if ((outfd
= open(new_name
, O_CREAT
|O_EXCL
|O_RDWR
, 0600)) == -1) {
323 DEBUG(10,("backup_old_idmap: failed to open %s. Error %s\n",
324 new_name
, strerror(errno
) ));
328 if (fstat(idmap_tdb
->fd
, &st
) == -1) {
329 DEBUG(10,("backup_old_idmap: failed to fstat %s. Error %s\n",
330 idmap_name
, strerror(errno
) ));
334 size
= (SMB_OFF_T
)st
.st_size
;
336 if (transfer_file(idmap_tdb
->fd
, outfd
, size
) != size
) {
337 DEBUG(10,("backup_old_idmap: failed to copy %s. Error %s\n",
338 idmap_name
, strerror(errno
) ));
342 if (close(outfd
) == -1) {
343 DEBUG(10,("backup_old_idmap: failed to close %s. Error %s\n",
344 idmap_name
, strerror(errno
) ));
348 tdb_unlockall(idmap_tdb
);
355 tdb_unlockall(idmap_tdb
);
360 /*****************************************************************************
361 Convert the idmap database from an older version.
362 *****************************************************************************/
364 static BOOL
idmap_convert(const char *idmap_name
)
366 int32 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
367 BOOL bigendianheader
= (idmap_tdb
->flags
& TDB_BIGENDIAN
) ? True
: False
;
369 if (vers
== IDMAP_VERSION
)
373 /* Make a backup copy before doing anything else.... */
374 if (!backup_old_idmap(idmap_name
))
378 if (((vers
== -1) && bigendianheader
) || (IREV(vers
) == IDMAP_VERSION
)) {
379 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
381 * high and low records were created on a
382 * big endian machine and will need byte-reversing.
387 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
392 wm
= server_state
.uid_low
;
394 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
395 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
399 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
403 wm
= server_state
.gid_low
;
405 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
406 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
411 /* the old format stored as DOMAIN/rid - now we store the SID direct */
412 tdb_traverse(idmap_tdb
, convert_fn
, NULL
);
414 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) == -1) {
415 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
422 /*****************************************************************************
423 Initialise idmap database.
424 *****************************************************************************/
426 BOOL
winbindd_idmap_init(void)
430 if (!(idmap_tdb
= tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
431 TDB_DEFAULT
, O_RDWR
| O_CREAT
, 0600))) {
432 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
436 /* possibly convert from an earlier version */
437 if (!idmap_convert(lock_path("winbindd_idmap.tdb"))) {
438 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
442 /* Create high water marks for group and user id */
444 if (tdb_fetch_int32(idmap_tdb
, HWM_USER
) == -1) {
445 if (tdb_store_int32(idmap_tdb
, HWM_USER
, server_state
.uid_low
) == -1) {
446 DEBUG(0, ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
451 if (tdb_fetch_int32(idmap_tdb
, HWM_GROUP
) == -1) {
452 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, server_state
.gid_low
) == -1) {
453 DEBUG(0, ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
461 BOOL
winbindd_idmap_close(void)
464 return (tdb_close(idmap_tdb
) == 0);
468 /* Dump status information to log file. Display different stuff based on
471 Debug Level Information Displayed
472 =================================================================
473 0 Percentage of [ug]id range allocated
474 0 High water marks (next allocated ids)
479 void winbindd_idmap_status(void)
481 int user_hwm
, group_hwm
;
483 DEBUG(0, ("winbindd idmap status:\n"));
485 /* Get current high water marks */
487 if ((user_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
488 DEBUG(DUMP_INFO
, ("\tCould not get userid high water mark!\n"));
491 if ((group_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
492 DEBUG(DUMP_INFO
, ("\tCould not get groupid high water mark!\n"));
495 /* Display next ids to allocate */
497 if (user_hwm
!= -1) {
498 DEBUG(DUMP_INFO
, ("\tNext userid to allocate is %d\n", user_hwm
));
501 if (group_hwm
!= -1) {
502 DEBUG(DUMP_INFO
, ("\tNext groupid to allocate is %d\n", group_hwm
));
505 /* Display percentage of id range already allocated. */
507 if (user_hwm
!= -1) {
508 int num_users
= user_hwm
- server_state
.uid_low
;
509 int total_users
= server_state
.uid_high
- server_state
.uid_low
;
511 DEBUG(DUMP_INFO
, ("\tUser id range is %d%% full (%d of %d)\n",
512 num_users
* 100 / total_users
, num_users
,
516 if (group_hwm
!= -1) {
517 int num_groups
= group_hwm
- server_state
.gid_low
;
518 int total_groups
= server_state
.gid_high
- server_state
.gid_low
;
520 DEBUG(DUMP_INFO
, ("\tGroup id range is %d%% full (%d of %d)\n",
521 num_groups
* 100 / total_groups
, num_groups
,
525 /* Display complete mapping of users and groups to rids */