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.
26 #define DBGC_CLASS DBGC_WINBIND
28 /* High water mark keys */
30 #define HWM_GROUP "GROUP HWM"
31 #define HWM_USER "USER HWM"
33 /* idmap version determines auto-conversion */
34 #define IDMAP_VERSION 2
38 static TDB_CONTEXT
*idmap_tdb
;
40 /* Allocate either a user or group id from the pool */
42 static BOOL
allocate_id(uid_t
*id
, BOOL isgroup
)
46 /* Get current high water mark */
48 if ((hwm
= tdb_fetch_int32(idmap_tdb
,
49 isgroup
? HWM_GROUP
: HWM_USER
)) == -1) {
53 /* Return next available uid in list */
55 if ((isgroup
&& (hwm
> server_state
.gid_high
)) ||
56 (!isgroup
&& (hwm
> server_state
.uid_high
))) {
57 DEBUG(0, ("winbind %sid range full!\n", isgroup
? "g" : "u"));
67 /* Store new high water mark */
69 tdb_store_int32(idmap_tdb
, isgroup
? HWM_GROUP
: HWM_USER
, hwm
);
74 /* Get an id from a rid */
75 static BOOL
get_id_from_sid(DOM_SID
*sid
, uid_t
*id
, BOOL isgroup
)
81 /* Check if sid is present in database */
82 sid_to_string(keystr
, sid
);
85 key
.dsize
= strlen(keystr
) + 1;
87 data
= tdb_fetch(idmap_tdb
, key
);
93 /* Parse and return existing uid */
94 fstrcpy(scanstr
, isgroup
? "GID" : "UID");
95 fstrcat(scanstr
, " %d");
97 if (sscanf(data
.dptr
, scanstr
, &the_id
) == 1) {
106 SAFE_FREE(data
.dptr
);
109 /* Allocate a new id for this sid */
111 if (id
&& allocate_id(id
, isgroup
)) {
116 slprintf(keystr2
, sizeof(keystr2
), "%s %d", isgroup
? "GID" : "UID", *id
);
119 data
.dsize
= strlen(keystr2
) + 1;
121 tdb_store(idmap_tdb
, key
, data
, TDB_REPLACE
);
122 tdb_store(idmap_tdb
, data
, key
, TDB_REPLACE
);
131 /* Get a uid from a user sid */
132 BOOL
winbindd_idmap_get_uid_from_sid(DOM_SID
*sid
, uid_t
*uid
)
134 return get_id_from_sid(sid
, uid
, False
);
137 /* Get a gid from a group sid */
138 BOOL
winbindd_idmap_get_gid_from_sid(DOM_SID
*sid
, gid_t
*gid
)
140 return get_id_from_sid(sid
, gid
, True
);
143 /* Get a uid from a user rid */
144 BOOL
winbindd_idmap_get_uid_from_rid(const char *dom_name
, uint32 rid
, uid_t
*uid
)
146 struct winbindd_domain
*domain
;
149 if (!(domain
= find_domain_from_name(dom_name
))) {
153 sid_copy(&sid
, &domain
->sid
);
154 sid_append_rid(&sid
, rid
);
156 return get_id_from_sid(&sid
, uid
, False
);
159 /* Get a gid from a group rid */
160 BOOL
winbindd_idmap_get_gid_from_rid(const char *dom_name
, uint32 rid
, gid_t
*gid
)
162 struct winbindd_domain
*domain
;
165 if (!(domain
= find_domain_from_name(dom_name
))) {
169 sid_copy(&sid
, &domain
->sid
);
170 sid_append_rid(&sid
, rid
);
172 return get_id_from_sid(&sid
, gid
, True
);
176 BOOL
get_sid_from_id(int id
, DOM_SID
*sid
, BOOL isgroup
)
182 slprintf(keystr
, sizeof(keystr
), "%s %d", isgroup
? "GID" : "UID", id
);
185 key
.dsize
= strlen(keystr
) + 1;
187 data
= tdb_fetch(idmap_tdb
, key
);
190 result
= string_to_sid(sid
, data
.dptr
);
191 SAFE_FREE(data
.dptr
);
197 /* Get a sid from a uid */
198 BOOL
winbindd_idmap_get_sid_from_uid(uid_t uid
, DOM_SID
*sid
)
200 return get_sid_from_id((int)uid
, sid
, False
);
203 /* Get a sid from a gid */
204 BOOL
winbindd_idmap_get_sid_from_gid(gid_t gid
, DOM_SID
*sid
)
206 return get_sid_from_id((int)gid
, sid
, True
);
209 /* Get a user rid from a uid */
210 BOOL
winbindd_idmap_get_rid_from_uid(uid_t uid
, uint32
*user_rid
,
211 struct winbindd_domain
**domain
)
215 if (!get_sid_from_id((int)uid
, &sid
, False
)) {
219 *domain
= find_domain_from_sid(&sid
);
220 if (! *domain
) return False
;
222 sid_split_rid(&sid
, user_rid
);
227 /* Get a group rid from a gid */
229 BOOL
winbindd_idmap_get_rid_from_gid(gid_t gid
, uint32
*group_rid
,
230 struct winbindd_domain
**domain
)
234 if (!get_sid_from_id((int)gid
, &sid
, True
)) {
238 *domain
= find_domain_from_sid(&sid
);
239 if (! *domain
) return False
;
241 sid_split_rid(&sid
, group_rid
);
246 /* convert one record to the new format */
247 static int convert_fn(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA data
, void *ignored
)
249 struct winbindd_domain
*domain
;
257 p
= strchr(key
.dptr
, '/');
262 fstrcpy(dom_name
, key
.dptr
);
265 domain
= find_domain_from_name(dom_name
);
267 /* We must delete the old record. */
268 DEBUG(0,("winbindd: convert_fn : Unable to find domain %s\n", dom_name
));
269 DEBUG(0,("winbindd: convert_fn : deleting record %s\n", key
.dptr
));
270 tdb_delete(idmap_tdb
, key
);
276 sid_copy(&sid
, &domain
->sid
);
277 sid_append_rid(&sid
, rid
);
279 sid_to_string(keystr
, &sid
);
281 key2
.dsize
= strlen(keystr
) + 1;
283 if (tdb_store(idmap_tdb
, key2
, data
, TDB_INSERT
) != 0) {
285 DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", key2
.dptr
));
286 DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n"));
290 if (tdb_store(idmap_tdb
, data
, key2
, TDB_REPLACE
) != 0) {
292 DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", data
.dptr
));
293 DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n"));
297 tdb_delete(idmap_tdb
, key
);
303 /*****************************************************************************
304 Make a backup copy of the old idmap just to be safe.... JRA.
305 *****************************************************************************/
307 static BOOL
backup_old_idmap(const char *idmap_name
)
314 pstrcpy(new_name
, idmap_name
);
315 pstrcat(new_name
, ".bak");
317 DEBUG(10,("backup_old_idmap: backing up %s to %s before upgrade.\n",
318 idmap_name
, new_name
));
320 if (tdb_lockall(idmap_tdb
) == -1) {
321 DEBUG(10,("backup_old_idmap: failed to lock %s. Error %s\n",
322 idmap_name
, tdb_errorstr(idmap_tdb
) ));
325 if ((outfd
= open(new_name
, O_CREAT
|O_EXCL
|O_RDWR
, 0600)) == -1) {
326 DEBUG(10,("backup_old_idmap: failed to open %s. Error %s\n",
327 new_name
, strerror(errno
) ));
331 if (fstat(idmap_tdb
->fd
, &st
) == -1) {
332 DEBUG(10,("backup_old_idmap: failed to fstat %s. Error %s\n",
333 idmap_name
, strerror(errno
) ));
337 size
= (SMB_OFF_T
)st
.st_size
;
339 if (transfer_file(idmap_tdb
->fd
, outfd
, size
) != size
) {
340 DEBUG(10,("backup_old_idmap: failed to copy %s. Error %s\n",
341 idmap_name
, strerror(errno
) ));
345 if (close(outfd
) == -1) {
346 DEBUG(10,("backup_old_idmap: failed to close %s. Error %s\n",
347 idmap_name
, strerror(errno
) ));
351 tdb_unlockall(idmap_tdb
);
358 tdb_unlockall(idmap_tdb
);
363 /*****************************************************************************
364 Convert the idmap database from an older version.
365 *****************************************************************************/
367 static BOOL
idmap_convert(const char *idmap_name
)
369 int32 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
370 BOOL bigendianheader
= (idmap_tdb
->flags
& TDB_BIGENDIAN
) ? True
: False
;
372 if (vers
== IDMAP_VERSION
)
376 /* Make a backup copy before doing anything else.... */
377 if (!backup_old_idmap(idmap_name
))
381 if (((vers
== -1) && bigendianheader
) || (IREV(vers
) == IDMAP_VERSION
)) {
382 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
384 * high and low records were created on a
385 * big endian machine and will need byte-reversing.
390 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
395 wm
= server_state
.uid_low
;
397 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
398 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
402 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
406 wm
= server_state
.gid_low
;
408 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
409 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
414 /* the old format stored as DOMAIN/rid - now we store the SID direct */
415 tdb_traverse(idmap_tdb
, convert_fn
, NULL
);
417 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) == -1) {
418 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
425 /*****************************************************************************
426 Initialise idmap database.
427 *****************************************************************************/
429 BOOL
winbindd_idmap_init(void)
433 if (!(idmap_tdb
= tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
434 TDB_DEFAULT
, O_RDWR
| O_CREAT
, 0600))) {
435 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
439 /* possibly convert from an earlier version */
440 if (!idmap_convert(lock_path("winbindd_idmap.tdb"))) {
441 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
445 /* Create high water marks for group and user id */
447 if (tdb_fetch_int32(idmap_tdb
, HWM_USER
) == -1) {
448 if (tdb_store_int32(idmap_tdb
, HWM_USER
, server_state
.uid_low
) == -1) {
449 DEBUG(0, ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
454 if (tdb_fetch_int32(idmap_tdb
, HWM_GROUP
) == -1) {
455 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, server_state
.gid_low
) == -1) {
456 DEBUG(0, ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
464 BOOL
winbindd_idmap_close(void)
467 return (tdb_close(idmap_tdb
) == 0);
471 /* Dump status information to log file. Display different stuff based on
474 Debug Level Information Displayed
475 =================================================================
476 0 Percentage of [ug]id range allocated
477 0 High water marks (next allocated ids)
482 void winbindd_idmap_status(void)
484 int user_hwm
, group_hwm
;
486 DEBUG(0, ("winbindd idmap status:\n"));
488 /* Get current high water marks */
490 if ((user_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
491 DEBUG(DUMP_INFO
, ("\tCould not get userid high water mark!\n"));
494 if ((group_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
495 DEBUG(DUMP_INFO
, ("\tCould not get groupid high water mark!\n"));
498 /* Display next ids to allocate */
500 if (user_hwm
!= -1) {
501 DEBUG(DUMP_INFO
, ("\tNext userid to allocate is %d\n", user_hwm
));
504 if (group_hwm
!= -1) {
505 DEBUG(DUMP_INFO
, ("\tNext groupid to allocate is %d\n", group_hwm
));
508 /* Display percentage of id range already allocated. */
510 if (user_hwm
!= -1) {
511 int num_users
= user_hwm
- server_state
.uid_low
;
512 int total_users
= server_state
.uid_high
- server_state
.uid_low
;
514 DEBUG(DUMP_INFO
, ("\tUser id range is %d%% full (%d of %d)\n",
515 num_users
* 100 / total_users
, num_users
,
519 if (group_hwm
!= -1) {
520 int num_groups
= group_hwm
- server_state
.gid_low
;
521 int total_groups
= server_state
.gid_high
- server_state
.gid_low
;
523 DEBUG(DUMP_INFO
, ("\tGroup id range is %d%% full (%d of %d)\n",
524 num_groups
* 100 / total_groups
, num_groups
,
528 /* Display complete mapping of users and groups to rids */