From d91a7b31629c721b2ae632fa5c8347529f0b44ff Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Thu, 5 Nov 1998 16:54:07 +0000 Subject: the start of the start of the SAM database API (This used to be commit 3eacd3013cc909e6e731a1a42f0aa7f202673bb9) --- source3/groupdb/aliasdb.c | 389 ++++++++++++++++++++++++++++++++++++++++++ source3/groupdb/aliasfile.c | 293 +++++++++++++++++++++++++++++++ source3/groupdb/groupdb.c | 385 +++++++++++++++++++++++++++++++++++++++++ source3/groupdb/groupfile.c | 282 ++++++++++++++++++++++++++++++ source3/passdb/passgrp.c | 221 ++++++++++++++++++++++++ source3/passdb/smbpassgroup.c | 196 +++++++++++++++++++++ 6 files changed, 1766 insertions(+) create mode 100644 source3/groupdb/aliasdb.c create mode 100644 source3/groupdb/aliasfile.c create mode 100644 source3/groupdb/groupdb.c create mode 100644 source3/groupdb/groupfile.c create mode 100644 source3/passdb/passgrp.c create mode 100644 source3/passdb/smbpassgroup.c (limited to 'source3') diff --git a/source3/groupdb/aliasdb.c b/source3/groupdb/aliasdb.c new file mode 100644 index 0000000000..573736d7f5 --- /dev/null +++ b/source3/groupdb/aliasdb.c @@ -0,0 +1,389 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Pasesword and authentication handling + Copyright (C) Jeremy Allison 1996-1998 + Copyright (C) Luke Kenneth Caseson Leighton 1996-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mases Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +extern fstring global_sam_name; + +/* + * NOTE. All these functions are abstracted into a structure + * that points to the correct function for the selected database. JRA. + */ + +static struct aliasdb_ops *aldb_ops; + +/*************************************************************** + Initialise the alias db operations. +***************************************************************/ + +BOOL initialise_alias_db(void) +{ + if (aldb_ops) + { + return True; + } + +#ifdef WITH_NISPLUS + aldb_ops = nisplus_initialise_alias_db(); +#elif defined(WITH_LDAP) + aldb_ops = ldap_initialise_alias_db(); +#else + aldb_ops = file_initialise_alias_db(); +#endif + + return (aldb_ops != NULL); +} + +/* + * Functions that return/manipulate a LOCAL_GRP. + */ + +/************************************************************************ + Utility function to search alias database by gid: the LOCAL_GRP + structure does not have a gid member, so we have to convert here + from gid to alias rid. +*************************************************************************/ +LOCAL_GRP *iterate_getaliasgid(gid_t gid, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + return iterate_getaliasrid(pwdb_gid_to_alias_rid(gid), mem, num_mem); +} + +/************************************************************************ + Utility function to search alias database by rid. use this if your database + does not have search facilities. +*************************************************************************/ +LOCAL_GRP *iterate_getaliasrid(uint32 rid, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + LOCAL_GRP *als = NULL; + void *fp = NULL; + + DEBUG(10, ("search by rid: 0x%x\n", rid)); + + /* Open the alias database file - not for update. */ + fp = startaliasent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open alias database.\n")); + return NULL; + } + + while ((als = getaliasent(fp, mem, num_mem)) != NULL && als->rid != rid) + { + } + + if (als != NULL) + { + DEBUG(10, ("found alias %s by rid: 0x%x\n", als->name, rid)); + } + + endaliasent(fp); + return als; +} + +/************************************************************************ + Utility function to search alias database by name. use this if your database + does not have search facilities. +*************************************************************************/ +LOCAL_GRP *iterate_getaliasnam(char *name, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + LOCAL_GRP *als = NULL; + void *fp = NULL; + + DEBUG(10, ("search by name: %s\n", name)); + + /* Open the alias database file - not for update. */ + fp = startaliasent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open alias database.\n")); + return NULL; + } + + while ((als = getaliasent(fp, mem, num_mem)) != NULL && !strequal(als->name, name)) + { + } + + if (als != NULL) + { + DEBUG(10, ("found by name: %s\n", name)); + } + + endaliasent(fp); + return als; +} + +/************************************************************************* + Routine to return the next entry in the smbdomainalias list. + *************************************************************************/ +BOOL add_domain_alias(LOCAL_GRP **alss, int *num_alss, LOCAL_GRP *als) +{ + if (alss == NULL || num_alss == NULL || als == NULL) + { + return False; + } + + (*alss) = Realloc((*alss), ((*num_alss)+1) * sizeof(LOCAL_GRP)); + if ((*alss) == NULL) + { + return False; + } + + DEBUG(10,("adding alias %s(%s)\n", als->name, als->comment)); + + fstrcpy((*alss)[(*num_alss)].name , als->name); + fstrcpy((*alss)[(*num_alss)].comment, als->comment); + (*alss)[(*num_alss)].rid = als->rid; + + (*num_alss)++; + + return True; +} + +/************************************************************************* + checks to see if a user is a member of a domain alias + *************************************************************************/ +static BOOL user_is_member(char *user_name, LOCAL_GRP_MEMBER *mem, int num_mem) +{ + int i; + pstring name; + snprintf(name, sizeof(name), "\\%s\\%s", global_sam_name, user_name); + + for (i = 0; i < num_mem; i++) + { + DEBUG(10,("searching against user %s...\n", mem[i].name)); + if (strequal(mem[i].name, name)) + { + DEBUG(10,("searching for user %s: found\n", name)); + return True; + } + } + DEBUG(10,("searching for user %s: not found\n", name)); + return False; +} + +/************************************************************************* + gets an array of aliases that a user is in. use this if your database + does not have search facilities + *************************************************************************/ +BOOL iterate_getuseraliasnam(char *user_name, LOCAL_GRP **alss, int *num_alss) +{ + LOCAL_GRP *als; + LOCAL_GRP_MEMBER *mem = NULL; + int num_mem = 0; + void *fp = NULL; + + DEBUG(10, ("search for useralias by name: %s\n", user_name)); + + if (user_name == NULL || als == NULL || num_alss == NULL) + { + return False; + } + + (*alss) = NULL; + (*num_alss) = 0; + + /* Open the alias database file - not for update. */ + fp = startaliasent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open alias database.\n")); + return False; + } + + /* iterate through all aliases. search members for required user */ + while ((als = getaliasent(fp, &mem, &num_mem)) != NULL) + { + DEBUG(5,("alias name %s members: %d\n", als->name, num_mem)); + if (num_mem != 0 && mem != NULL) + { + BOOL ret = True; + if (user_is_member(user_name, mem, num_mem)) + { + ret = add_domain_alias(alss, num_alss, als); + } + + free(mem); + mem = NULL; + num_mem = 0; + + if (!ret) + { + (*num_alss) = 0; + break; + } + } + } + + if ((*num_alss) != 0) + { + DEBUG(10, ("found %d user aliases:\n", (*num_alss))); + } + + endaliasent(fp); + return True; +} + +/************************************************************************* + gets an array of aliases that a user is in. use this if your database + does not have search facilities + *************************************************************************/ +BOOL enumdomaliases(LOCAL_GRP **alss, int *num_alss) +{ + LOCAL_GRP *als; + void *fp = NULL; + + DEBUG(10, ("enum user aliases\n")); + + if (als == NULL || num_alss == NULL) + { + return False; + } + + (*alss) = NULL; + (*num_alss) = 0; + + /* Open the alias database file - not for update. */ + fp = startaliasent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open alias database.\n")); + return False; + } + + /* iterate through all aliases. */ + while ((als = getaliasent(fp, NULL, NULL)) != NULL) + { + if (!add_domain_alias(alss, num_alss, als)) + { + DEBUG(0,("unable to add alias while enumerating\n")); + return False; + } + } + + if ((*num_alss) != 0) + { + DEBUG(10, ("found %d user aliases:\n", (*num_alss))); + } + + endaliasent(fp); + return True; +} + +/*************************************************************** + Start to enumerate the alias database list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +void *startaliasent(BOOL update) +{ + return aldb_ops->startaliasent(update); +} + +/*************************************************************** + End enumeration of the alias database list. +****************************************************************/ + +void endaliasent(void *vp) +{ + aldb_ops->endaliasent(vp); +} + +/************************************************************************* + Routine to return the next entry in the alias database list. + *************************************************************************/ + +LOCAL_GRP *getaliasent(void *vp, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + return aldb_ops->getaliasent(vp, mem, num_mem); +} + +/************************************************************************ + Routine to add an entry to the alias database file. +*************************************************************************/ + +BOOL add_alias_entry(LOCAL_GRP *newals) +{ + return aldb_ops->add_alias_entry(newals); +} + +/************************************************************************ + Routine to search the alias database file for an entry matching the aliasname. + and then replace the entry. +************************************************************************/ + +BOOL mod_alias_entry(LOCAL_GRP* als) +{ + return aldb_ops->mod_alias_entry(als); +} + +/************************************************************************ + Routine to search alias database by name. +*************************************************************************/ + +LOCAL_GRP *getaliasnam(char *name, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + return aldb_ops->getaliasnam(name, mem, num_mem); +} + +/************************************************************************ + Routine to search alias database by alias rid. +*************************************************************************/ + +LOCAL_GRP *getaliasrid(uint32 alias_rid, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + return aldb_ops->getaliasrid(alias_rid, mem, num_mem); +} + +/************************************************************************ + Routine to search alias database by gid. +*************************************************************************/ + +LOCAL_GRP *getaliasgid(gid_t gid, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + return aldb_ops->getaliasgid(gid, mem, num_mem); +} + +/************************************************************************* + gets an array of aliases that a user is in. + *************************************************************************/ +BOOL getuseraliasnam(char *user_name, LOCAL_GRP **als, int *num_alss) +{ + return aldb_ops->getuseraliasnam(user_name, als, num_alss); +} + +/************************************************************* + initialises a LOCAL_GRP. + **************************************************************/ + +void aldb_init_als(LOCAL_GRP *als) +{ + if (als == NULL) return; + ZERO_STRUCTP(als); +} + diff --git a/source3/groupdb/aliasfile.c b/source3/groupdb/aliasfile.c new file mode 100644 index 0000000000..0c1b3a3d81 --- /dev/null +++ b/source3/groupdb/aliasfile.c @@ -0,0 +1,293 @@ +/* + * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup + * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +#ifdef USE_SMBPASS_DB + +static int al_file_lock_depth = 0; +extern int DEBUGLEVEL; + +static char s_readbuf[1024]; + +/*************************************************************** + Start to enumerate the aliasdb list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +static void *startalsfilepwent(BOOL update) +{ + return startfilepwent(lp_smb_alias_file(), + s_readbuf, sizeof(s_readbuf), + &al_file_lock_depth, update); +} + +/*************************************************************** + End enumeration of the aliasdb list. +****************************************************************/ + +static void endalsfilepwent(void *vp) +{ + endfilepwent(vp, &al_file_lock_depth); +} + +/************************************************************************* + Return the current position in the aliasdb list as an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ +static SMB_BIG_UINT getalsfilepwpos(void *vp) +{ + return getfilepwpos(vp); +} + +/************************************************************************* + Set the current position in the aliasdb list from an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ +static BOOL setalsfilepwpos(void *vp, SMB_BIG_UINT tok) +{ + return setfilepwpos(vp, tok); +} + +static BOOL make_alias_line(char *p, int max_len, + LOCAL_GRP *als, + LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + int i; + int len; + len = snprintf(p, max_len, "%s:%s:%d:", als->name, als->comment, als->rid); + + if (len == -1) + { + DEBUG(0,("make_alias_line: cannot create entry\n")); + return False; + } + + p += len; + max_len -= len; + + if (mem == NULL || num_mem == NULL) + { + return True; + } + + for (i = 0; i < (*num_mem); i++) + { + len = strlen((*mem)[i].name); + p = safe_strcpy(p, (*mem)[i].name, max_len); + + if (p == NULL) + { + DEBUG(0, ("make_alias_line: out of space for aliases!\n")); + return False; + } + + max_len -= len; + + if (i != (*num_mem)-1) + { + *p = ','; + p++; + max_len--; + } + } + + return True; +} + +/************************************************************************* + Routine to return the next entry in the smbdomainalias list. + *************************************************************************/ +static char *get_alias_members(char *p, int *num_mem, LOCAL_GRP_MEMBER **members) +{ + fstring name; + + if (num_mem == NULL || members == NULL) + { + return NULL; + } + + (*num_mem) = 0; + (*members) = NULL; + + while (next_token(&p, name, ",", sizeof(fstring))) + { + DOM_SID sid; + uint8 type; + + if (lookup_sid(name, &sid, &type)) + { + (*members) = Realloc((*members), ((*num_mem)+1) * sizeof(LOCAL_GRP_MEMBER)); + (*num_mem)++; + } + else + { + DEBUG(0,("alias database: could not resolve alias named %s\n", name)); + continue; + } + if ((*members) == NULL) + { + return NULL; + } + fstrcpy((*members)[(*num_mem)-1].name, name); + (*members)[(*num_mem)-1].sid_use = type; + sid_copy(&(*members)[(*num_mem)-1].sid, &sid); + } + return p; +} + +/************************************************************************* + Routine to return the next entry in the smbdomainalias list. + *************************************************************************/ +static LOCAL_GRP *getalsfilepwent(void *vp, LOCAL_GRP_MEMBER **mem, int *num_mem) +{ + /* Static buffers we will return. */ + static LOCAL_GRP al_buf; + + int gidval; + + pstring linebuf; + char *p; + size_t linebuf_len; + + aldb_init_als(&al_buf); + + /* + * Scan the file, a line at a time and check if the name matches. + */ + while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0) + { + /* get alias name */ + + p = strncpyn(al_buf.name, linebuf, sizeof(al_buf.name), ':'); + if (p == NULL) + { + DEBUG(0, ("getalsfilepwent: malformed alias entry (no :)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* get alias comment */ + + p = strncpyn(al_buf.comment, p, sizeof(al_buf.comment), ':'); + if (p == NULL) + { + DEBUG(0, ("getalsfilepwent: malformed alias entry (no :)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* Get alias gid. */ + + p = Atoic(p, &gidval, ":"); + + if (p == NULL) + { + DEBUG(0, ("getalsfilepwent: malformed alias entry (no : after uid)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* now get the user's aliases. there are a maximum of 32 */ + + if (mem != NULL && num_mem != NULL) + { + (*mem) = NULL; + (*num_mem) = 0; + + p = get_alias_members(p, num_mem, mem); + if (p == NULL) + { + DEBUG(0, ("getalsfilepwent: malformed alias entry (no : after members)\n")); + } + } + + /* ok, set up the static data structure and return it */ + + al_buf.rid = pwdb_gid_to_alias_rid((gid_t)gidval); + + make_alias_line(linebuf, sizeof(linebuf), &al_buf, mem, num_mem); + DEBUG(10,("line: '%s'\n", linebuf)); + + return &al_buf; + } + + DEBUG(5,("getalsfilepwent: end of file reached.\n")); + return NULL; +} + +/************************************************************************ + Routine to add an entry to the aliasdb file. +*************************************************************************/ + +static BOOL add_alsfileals_entry(LOCAL_GRP *newals) +{ + DEBUG(0, ("add_alsfileals_entry: NOT IMPLEMENTED\n")); + return False; +} + +/************************************************************************ + Routine to search the aliasdb file for an entry matching the aliasname. + and then modify its alias entry. We can't use the startalspwent()/ + getalspwent()/endalspwent() interfaces here as we depend on looking + in the actual file to decide how much room we have to write data. + override = False, normal + override = True, override XXXXXXXX'd out alias or NO PASS +************************************************************************/ + +static BOOL mod_alsfileals_entry(LOCAL_GRP* als) +{ + DEBUG(0, ("mod_alsfileals_entry: NOT IMPLEMENTED\n")); + return False; +} + + +static struct aliasdb_ops file_ops = +{ + startalsfilepwent, + endalsfilepwent, + getalsfilepwpos, + setalsfilepwpos, + + iterate_getaliasnam, /* In aliasdb.c */ + iterate_getaliasgid, /* In aliasdb.c */ + iterate_getaliasrid, /* In aliasdb.c */ + getalsfilepwent, + + add_alsfileals_entry, + mod_alsfileals_entry, + + iterate_getuseraliasnam /* in aliasdb.c */ +}; + +struct aliasdb_ops *file_initialise_alias_db(void) +{ + return &file_ops; +} + +#else + /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */ + void als_dummy_function(void) { } /* stop some compilers complaining */ +#endif /* USE_SMBPASS_DB */ diff --git a/source3/groupdb/groupdb.c b/source3/groupdb/groupdb.c new file mode 100644 index 0000000000..b8952358fb --- /dev/null +++ b/source3/groupdb/groupdb.c @@ -0,0 +1,385 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Jeremy Allison 1996-1998 + Copyright (C) Luke Kenneth Casson Leighton 1996-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +/* + * NOTE. All these functions are abstracted into a structure + * that points to the correct function for the selected database. JRA. + */ + +static struct groupdb_ops *gpdb_ops; + +/*************************************************************** + Initialise the group db operations. +***************************************************************/ + +BOOL initialise_group_db(void) +{ + if (gpdb_ops) + { + return True; + } + +#ifdef WITH_NISPLUS + gpdb_ops = nisplus_initialise_group_db(); +#elif defined(WITH_LDAP) + gpdb_ops = ldap_initialise_group_db(); +#else + gpdb_ops = file_initialise_group_db(); +#endif + + return (gpdb_ops != NULL); +} + +/* + * Functions that return/manipulate a DOMAIN_GRP. + */ + +/************************************************************************ + Utility function to search group database by gid: the DOMAIN_GRP + structure does not have a gid member, so we have to convert here + from gid to group rid. +*************************************************************************/ +DOMAIN_GRP *iterate_getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + return iterate_getgrouprid(pwdb_gid_to_group_rid(gid), mem, num_mem); +} + +/************************************************************************ + Utility function to search group database by rid. use this if your database + does not have search facilities. +*************************************************************************/ +DOMAIN_GRP *iterate_getgrouprid(uint32 rid, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + DOMAIN_GRP *grp = NULL; + void *fp = NULL; + + DEBUG(10, ("search by rid: 0x%x\n", rid)); + + /* Open the group database file - not for update. */ + fp = startgroupent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open group database.\n")); + return NULL; + } + + while ((grp = getgroupent(fp, mem, num_mem)) != NULL && grp->rid != rid) + { + } + + if (grp != NULL) + { + DEBUG(10, ("found group %s by rid: 0x%x\n", grp->name, rid)); + } + + endgroupent(fp); + return grp; +} + +/************************************************************************ + Utility function to search group database by name. use this if your database + does not have search facilities. +*************************************************************************/ +DOMAIN_GRP *iterate_getgroupnam(char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + DOMAIN_GRP *grp = NULL; + void *fp = NULL; + + DEBUG(10, ("search by name: %s\n", name)); + + /* Open the group database file - not for update. */ + fp = startgroupent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open group database.\n")); + return NULL; + } + + while ((grp = getgroupent(fp, mem, num_mem)) != NULL && !strequal(grp->name, name)) + { + } + + if (grp != NULL) + { + DEBUG(10, ("found by name: %s\n", name)); + } + + endgroupent(fp); + return grp; +} + +/************************************************************************* + Routine to return the next entry in the smbdomaingroup list. + *************************************************************************/ +BOOL add_domain_group(DOMAIN_GRP **grps, int *num_grps, DOMAIN_GRP *grp) +{ + if (grps == NULL || num_grps == NULL || grp == NULL) + { + return False; + } + + (*grps) = Realloc((*grps), ((*num_grps)+1) * sizeof(DOMAIN_GRP)); + if ((*grps) == NULL) + { + return False; + } + + DEBUG(10,("adding group %s(%s)\n", grp->name, grp->comment)); + + fstrcpy((*grps)[(*num_grps)].name , grp->name); + fstrcpy((*grps)[(*num_grps)].comment, grp->comment); + (*grps)[(*num_grps)].attr = grp->attr; + (*grps)[(*num_grps)].rid = grp->rid ; + + (*num_grps)++; + + return True; +} + +/************************************************************************* + checks to see if a user is a member of a domain group + *************************************************************************/ +static BOOL user_is_member(char *user_name, DOMAIN_GRP_MEMBER *mem, int num_mem) +{ + int i; + for (i = 0; i < num_mem; i++) + { + DEBUG(10,("searching against user %s...\n", mem[i].name)); + if (strequal(mem[i].name, user_name)) + { + DEBUG(10,("searching for user %s: found\n", user_name)); + return True; + } + } + DEBUG(10,("searching for user %s: not found\n", user_name)); + return False; +} + +/************************************************************************* + gets an array of groups that a user is in. use this if your database + does not have search facilities + *************************************************************************/ +BOOL iterate_getusergroupsnam(char *user_name, DOMAIN_GRP **grps, int *num_grps) +{ + DOMAIN_GRP *grp; + DOMAIN_GRP_MEMBER *mem = NULL; + int num_mem = 0; + void *fp = NULL; + + DEBUG(10, ("search for usergroups by name: %s\n", user_name)); + + if (user_name == NULL || grp == NULL || num_grps == NULL) + { + return False; + } + + (*grps) = NULL; + (*num_grps) = 0; + + /* Open the group database file - not for update. */ + fp = startgroupent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open group database.\n")); + return False; + } + + /* iterate through all groups. search members for required user */ + while ((grp = getgroupent(fp, &mem, &num_mem)) != NULL) + { + DEBUG(5,("group name %s members: %d\n", grp->name, num_mem)); + if (num_mem != 0 && mem != NULL) + { + BOOL ret = True; + if (user_is_member(user_name, mem, num_mem)) + { + ret = add_domain_group(grps, num_grps, grp); + } + + free(mem); + mem = NULL; + num_mem = 0; + + if (!ret) + { + (*num_grps) = 0; + break; + } + } + } + + if ((*num_grps) != 0) + { + DEBUG(10, ("found %d user groups:\n", (*num_grps))); + } + + endgroupent(fp); + return True; +} + +/************************************************************************* + gets an array of groups that a user is in. use this if your database + does not have search facilities + *************************************************************************/ +BOOL enumdomgroups(DOMAIN_GRP **grps, int *num_grps) +{ + DOMAIN_GRP *grp; + void *fp = NULL; + + DEBUG(10, ("enum user groups\n")); + + if (grp == NULL || num_grps == NULL) + { + return False; + } + + (*grps) = NULL; + (*num_grps) = 0; + + /* Open the group database file - not for update. */ + fp = startgroupent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open group database.\n")); + return False; + } + + /* iterate through all groups. */ + while ((grp = getgroupent(fp, NULL, NULL)) != NULL) + { + if (!add_domain_group(grps, num_grps, grp)) + { + DEBUG(0,("unable to add group while enumerating\n")); + return False; + } + } + + if ((*num_grps) != 0) + { + DEBUG(10, ("found %d user groups:\n", (*num_grps))); + } + + endgroupent(fp); + return True; +} + +/*************************************************************** + Start to enumerate the group database list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +void *startgroupent(BOOL update) +{ + return gpdb_ops->startgroupent(update); +} + +/*************************************************************** + End enumeration of the group database list. +****************************************************************/ + +void endgroupent(void *vp) +{ + gpdb_ops->endgroupent(vp); +} + +/************************************************************************* + Routine to return the next entry in the group database list. + *************************************************************************/ + +DOMAIN_GRP *getgroupent(void *vp, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + return gpdb_ops->getgroupent(vp, mem, num_mem); +} + +/************************************************************************ + Routine to add an entry to the group database file. +*************************************************************************/ + +BOOL add_group_entry(DOMAIN_GRP *newgrp) +{ + return gpdb_ops->add_group_entry(newgrp); +} + +/************************************************************************ + Routine to search the group database file for an entry matching the groupname. + and then replace the entry. +************************************************************************/ + +BOOL mod_group_entry(DOMAIN_GRP* grp) +{ + return gpdb_ops->mod_group_entry(grp); +} + +/************************************************************************ + Routine to search group database by name. +*************************************************************************/ + +DOMAIN_GRP *getgroupnam(char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + return gpdb_ops->getgroupnam(name, mem, num_mem); +} + +/************************************************************************ + Routine to search group database by group rid. +*************************************************************************/ + +DOMAIN_GRP *getgrouprid(uint32 group_rid, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + return gpdb_ops->getgrouprid(group_rid, mem, num_mem); +} + +/************************************************************************ + Routine to search group database by gid. +*************************************************************************/ + +DOMAIN_GRP *getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + return gpdb_ops->getgroupgid(gid, mem, num_mem); +} + +/************************************************************************* + gets an array of groups that a user is in. + *************************************************************************/ +BOOL getusergroupsnam(char *user_name, DOMAIN_GRP **grp, int *num_grps) +{ + return gpdb_ops->getusergroupsnam(user_name, grp, num_grps); +} + +/************************************************************* + initialises a DOMAIN_GRP. + **************************************************************/ + +void gpdb_init_grp(DOMAIN_GRP *grp) +{ + if (grp == NULL) return; + ZERO_STRUCTP(grp); +} + diff --git a/source3/groupdb/groupfile.c b/source3/groupdb/groupfile.c new file mode 100644 index 0000000000..5f5a069f05 --- /dev/null +++ b/source3/groupdb/groupfile.c @@ -0,0 +1,282 @@ +/* + * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup + * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +#ifdef USE_SMBPASS_DB + +static int gp_file_lock_depth = 0; +extern int DEBUGLEVEL; + +static char s_readbuf[1024]; + +/*************************************************************** + Start to enumerate the grppasswd list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +static void *startgrpfilepwent(BOOL update) +{ + return startfilepwent(lp_smb_group_file(), + s_readbuf, sizeof(s_readbuf), + &gp_file_lock_depth, update); +} + +/*************************************************************** + End enumeration of the grppasswd list. +****************************************************************/ + +static void endgrpfilepwent(void *vp) +{ + endfilepwent(vp, &gp_file_lock_depth); +} + +/************************************************************************* + Return the current position in the grppasswd list as an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ +static SMB_BIG_UINT getgrpfilepwpos(void *vp) +{ + return getfilepwpos(vp); +} + +/************************************************************************* + Set the current position in the grppasswd list from an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ +static BOOL setgrpfilepwpos(void *vp, SMB_BIG_UINT tok) +{ + return setfilepwpos(vp, tok); +} + +static BOOL make_group_line(char *p, int max_len, + DOMAIN_GRP *grp, + DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + int i; + int len; + len = snprintf(p, max_len, "%s:%s:%d:", grp->name, grp->comment, grp->rid); + + if (len == -1) + { + DEBUG(0,("make_group_line: cannot create entry\n")); + return False; + } + + p += len; + max_len -= len; + + if (mem == NULL || num_mem == NULL) + { + return True; + } + + for (i = 0; i < (*num_mem); i++) + { + len = strlen((*mem)[i].name); + p = safe_strcpy(p, (*mem)[i].name, max_len); + + if (p == NULL) + { + DEBUG(0, ("make_group_line: out of space for groups!\n")); + return False; + } + + max_len -= len; + + if (i != (*num_mem)-1) + { + *p = ','; + p++; + max_len--; + } + } + + return True; +} + +/************************************************************************* + Routine to return the next entry in the smbdomaingroup list. + *************************************************************************/ +static char *get_group_members(char *p, int *num_mem, DOMAIN_GRP_MEMBER **members) +{ + fstring name; + + if (num_mem == NULL || members == NULL) + { + return NULL; + } + + (*num_mem) = 0; + (*members) = NULL; + + while (next_token(&p, name, ",", sizeof(fstring))) + { + (*members) = Realloc((*members), ((*num_mem)+1) * sizeof(DOMAIN_GRP_MEMBER)); + if ((*members) == NULL) + { + return NULL; + } + fstrcpy((*members)[(*num_mem)].name, name); + (*members)[(*num_mem)].attr = 0x07; + (*num_mem)++; + } + return p; +} + +/************************************************************************* + Routine to return the next entry in the smbdomaingroup list. + *************************************************************************/ +static DOMAIN_GRP *getgrpfilepwent(void *vp, DOMAIN_GRP_MEMBER **mem, int *num_mem) +{ + /* Static buffers we will return. */ + static DOMAIN_GRP gp_buf; + + int gidval; + + pstring linebuf; + char *p; + size_t linebuf_len; + + gpdb_init_grp(&gp_buf); + + /* + * Scan the file, a line at a time and check if the name matches. + */ + while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0) + { + /* get group name */ + + p = strncpyn(gp_buf.name, linebuf, sizeof(gp_buf.name), ':'); + if (p == NULL) + { + DEBUG(0, ("getgrpfilepwent: malformed group entry (no :)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* get group comment */ + + p = strncpyn(gp_buf.comment, p, sizeof(gp_buf.comment), ':'); + if (p == NULL) + { + DEBUG(0, ("getgrpfilepwent: malformed group entry (no :)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* Get group gid. */ + + p = Atoic(p, &gidval, ":"); + + if (p == NULL) + { + DEBUG(0, ("getgrpfilepwent: malformed group entry (no : after uid)\n")); + continue; + } + + /* Go past ':' */ + p++; + + /* now get the user's groups. there are a maximum of 32 */ + + if (mem != NULL && num_mem != NULL) + { + (*mem) = NULL; + (*num_mem) = 0; + + p = get_group_members(p, num_mem, mem); + if (p == NULL) + { + DEBUG(0, ("getgrpfilepwent: malformed group entry (no : after members)\n")); + } + } + + /* ok, set up the static data structure and return it */ + + gp_buf.rid = pwdb_gid_to_group_rid((gid_t)gidval); + gp_buf.attr = 0x07; + + make_group_line(linebuf, sizeof(linebuf), &gp_buf, mem, num_mem); + DEBUG(10,("line: '%s'\n", linebuf)); + + return &gp_buf; + } + + DEBUG(5,("getgrpfilepwent: end of file reached.\n")); + return NULL; +} + +/************************************************************************ + Routine to add an entry to the grppasswd file. +*************************************************************************/ + +static BOOL add_grpfilegrp_entry(DOMAIN_GRP *newgrp) +{ + DEBUG(0, ("add_grpfilegrp_entry: NOT IMPLEMENTED\n")); + return False; +} + +/************************************************************************ + Routine to search the grppasswd file for an entry matching the groupname. + and then modify its group entry. We can't use the startgrppwent()/ + getgrppwent()/endgrppwent() interfaces here as we depend on looking + in the actual file to decide how much room we have to write data. + override = False, normal + override = True, override XXXXXXXX'd out group or NO PASS +************************************************************************/ + +static BOOL mod_grpfilegrp_entry(DOMAIN_GRP* grp) +{ + DEBUG(0, ("mod_grpfilegrp_entry: NOT IMPLEMENTED\n")); + return False; +} + + +static struct groupdb_ops file_ops = +{ + startgrpfilepwent, + endgrpfilepwent, + getgrpfilepwpos, + setgrpfilepwpos, + + iterate_getgroupnam, /* In groupdb.c */ + iterate_getgroupgid, /* In groupdb.c */ + iterate_getgrouprid, /* In groupdb.c */ + getgrpfilepwent, + + add_grpfilegrp_entry, + mod_grpfilegrp_entry, + + iterate_getusergroupsnam /* in groupdb.c */ +}; + +struct groupdb_ops *file_initialise_group_db(void) +{ + return &file_ops; +} + +#else + /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */ + void grppass_dummy_function(void) { } /* stop some compilers complaining */ +#endif /* USE_SMBPASS_DB */ diff --git a/source3/passdb/passgrp.c b/source3/passdb/passgrp.c new file mode 100644 index 0000000000..ded9ef33d2 --- /dev/null +++ b/source3/passdb/passgrp.c @@ -0,0 +1,221 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Jeremy Allison 1996-1998 + Copyright (C) Luke Kenneth Casson Leighton 1996-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +/* + * NOTE. All these functions are abstracted into a structure + * that points to the correct function for the selected database. JRA. + * + * the API does NOT fill in the gaps if you set an API function + * to NULL: it will deliberately attempt to call the NULL function. + * + */ + +static struct passgrp_ops *pwgrp_ops; + +/*************************************************************** + Initialise the passgrp operations. +***************************************************************/ + +BOOL initialise_passgrp_db(void) +{ + if (pwgrp_ops) + { + return True; + } + +#ifdef WITH_NISPLUS + pwgrp_ops = nisplus_initialise_password_grp(); +#elif defined(WITH_LDAP) + pwgrp_ops = ldap_initialise_password_grp(); +#else + pwgrp_ops = file_initialise_password_grp(); +#endif + + return (pwgrp_ops != NULL); +} + +/* + * Functions that return/manipulate a struct smb_passwd. + */ + +/************************************************************************ + Utility function to search smb passwd by rid. +*************************************************************************/ + +struct smb_passwd *iterate_getsmbgrprid(uint32 user_rid, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + return iterate_getsmbgrpuid(pwdb_user_rid_to_uid(user_rid), + grps, num_grps, alss, num_alss); +} + +/************************************************************************ + Utility function to search smb passwd by uid. use this if your database + does not have search facilities. +*************************************************************************/ + +struct smb_passwd *iterate_getsmbgrpuid(uid_t smb_userid, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + struct smb_passwd *pwd = NULL; + void *fp = NULL; + + DEBUG(10, ("search by smb_userid: %x\n", (int)smb_userid)); + + /* Open the smb password database - not for update. */ + fp = startsmbgrpent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open smb passgrp database.\n")); + return NULL; + } + + while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && pwd->smb_userid != smb_userid) + ; + + if (pwd != NULL) + { + DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid)); + } + + endsmbgrpent(fp); + return pwd; +} + +/************************************************************************ + Utility function to search smb passwd by name. use this if your database + does not have search facilities. +*************************************************************************/ + +struct smb_passwd *iterate_getsmbgrpnam(char *name, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + struct smb_passwd *pwd = NULL; + void *fp = NULL; + + DEBUG(10, ("search by name: %s\n", name)); + + /* Open the passgrp file - not for update. */ + fp = startsmbgrpent(False); + + if (fp == NULL) + { + DEBUG(0, ("unable to open smb passgrp database.\n")); + return NULL; + } + + while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && !strequal(pwd->smb_name, name)) + ; + + if (pwd != NULL) + { + DEBUG(10, ("found by name: %s\n", name)); + } + + endsmbgrpent(fp); + return pwd; +} + +/*************************************************************** + Start to enumerate the smb or sam passwd list. Returns a void pointer + to ensure no modification outside this module. + + Note that currently it is being assumed that a pointer returned + from this function may be used to enumerate struct sam_passwd + entries as well as struct smb_passwd entries. This may need + to change. JRA. + +****************************************************************/ + +void *startsmbgrpent(BOOL update) +{ + return pwgrp_ops->startsmbgrpent(update); +} + +/*************************************************************** + End enumeration of the smb or sam passwd list. + + Note that currently it is being assumed that a pointer returned + from this function may be used to enumerate struct sam_passwd + entries as well as struct smb_passwd entries. This may need + to change. JRA. + +****************************************************************/ + +void endsmbgrpent(void *vp) +{ + pwgrp_ops->endsmbgrpent(vp); +} + +/************************************************************************* + Routine to return the next entry in the smb passwd list. + *************************************************************************/ + +struct smb_passwd *getsmbgrpent(void *vp, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + return pwgrp_ops->getsmbgrpent(vp, grps, num_grps, alss, num_alss); +} + +/************************************************************************ + Routine to search smb passwd by name. +*************************************************************************/ + +struct smb_passwd *getsmbgrpnam(char *name, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + return pwgrp_ops->getsmbgrpnam(name, grps, num_grps, alss, num_alss); +} + +/************************************************************************ + Routine to search smb passwd by user rid. +*************************************************************************/ + +struct smb_passwd *getsmbgrprid(uint32 user_rid, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + return pwgrp_ops->getsmbgrprid(user_rid, grps, num_grps, alss, num_alss); +} + +/************************************************************************ + Routine to search smb passwd by uid. +*************************************************************************/ + +struct smb_passwd *getsmbgrpuid(uid_t smb_userid, + uint32 **grps, int *num_grps, + uint32 **alss, int *num_alss) +{ + return pwgrp_ops->getsmbgrpuid(smb_userid, grps, num_grps, alss, num_alss); +} + diff --git a/source3/passdb/smbpassgroup.c b/source3/passdb/smbpassgroup.c new file mode 100644 index 0000000000..4636c08c94 --- /dev/null +++ b/source3/passdb/smbpassgroup.c @@ -0,0 +1,196 @@ +/* + * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup + * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +#ifdef USE_SMBPASS_DB + +static int grp_file_lock_depth = 0; +extern int DEBUGLEVEL; + +/*************************************************************** + Start to enumerate the smbpasswd list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +static void *startsmbfilegrpent(BOOL update) +{ + static char s_readbuf[1024]; + return startfilepwent(lp_smb_passgrp_file(), s_readbuf, sizeof(s_readbuf), + &grp_file_lock_depth, update); +} + +/*************************************************************** + End enumeration of the smbpasswd list. +****************************************************************/ + +static void endsmbfilegrpent(void *vp) +{ + endfilepwent(vp, &grp_file_lock_depth); +} + +/************************************************************************* + Return the current position in the smbpasswd list as an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ + +static SMB_BIG_UINT getsmbfilegrppos(void *vp) +{ + return getfilepwpos(vp); +} + +/************************************************************************* + Set the current position in the smbpasswd list from an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ + +static BOOL setsmbfilegrppos(void *vp, SMB_BIG_UINT tok) +{ + return setfilepwpos(vp, tok); +} + +/************************************************************************* + Routine to return the next entry in the smbpasswd list. + *************************************************************************/ +static struct smb_passwd *getsmbfilegrpent(void *vp, + uint32 **grp_rids, int *num_grps, + uint32 **als_rids, int *num_alss) +{ + /* Static buffers we will return. */ + static struct smb_passwd pw_buf; + static pstring user_name; + struct passwd *pwfile; + pstring linebuf; + unsigned char *p; + int uidval; + size_t linebuf_len; + + if (vp == NULL) + { + DEBUG(0,("getsmbfilegrpent: Bad password file pointer.\n")); + return NULL; + } + + pwdb_init_smb(&pw_buf); + + /* + * Scan the file, a line at a time. + */ + while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0) + { + /* + * The line we have should be of the form :- + * + * username:uid:domainrid1,domainrid2..:aliasrid1,aliasrid2..: + */ + + /* + * As 256 is shorter than a pstring we don't need to check + * length here - if this ever changes.... + */ + p = strncpyn(user_name, linebuf, sizeof(user_name), ':'); + + /* Go past ':' */ + p++; + + /* Get smb uid. */ + + p = Atoic((char *) p, &uidval, ":"); + + pw_buf.smb_name = user_name; + pw_buf.smb_userid = uidval; + + /* + * Now get the password value - this should be 32 hex digits + * which are the ascii representations of a 16 byte string. + * Get two at a time and put them into the password. + */ + + /* Skip the ':' */ + p++; + + if (grp_rids != NULL && num_grps != NULL) + { + int i; + p = get_numlist(p, grp_rids, num_grps); + if (p == NULL) + { + DEBUG(0,("getsmbfilegrpent: invalid line\n")); + return NULL; + } + for (i = 0; i < (*num_grps); i++) + { + (*grp_rids)[i] = pwdb_gid_to_group_rid((*grp_rids)[i]); + } + } + + /* Skip the ':' */ + p++; + + if (als_rids != NULL && num_alss != NULL) + { + int i; + p = get_numlist(p, als_rids, num_alss); + if (p == NULL) + { + DEBUG(0,("getsmbfilegrpent: invalid line\n")); + return NULL; + } + for (i = 0; i < (*num_alss); i++) + { + (*als_rids)[i] = pwdb_gid_to_alias_rid((*als_rids)[i]); + } + } + + pwfile = Get_Pwnam(pw_buf.smb_name, False); + if (pwfile == NULL) + { + DEBUG(0,("getsmbfilegrpent: smbpasswd database is corrupt!\n")); + DEBUG(0,("getsmbfilegrpent: username %s not in unix passwd database!\n", pw_buf.smb_name)); + return NULL; + } + + return &pw_buf; + } + + DEBUG(5,("getsmbfilegrpent: end of file reached.\n")); + return NULL; +} + +static struct passgrp_ops file_ops = +{ + startsmbfilegrpent, + endsmbfilegrpent, + getsmbfilegrppos, + setsmbfilegrppos, + iterate_getsmbgrpnam, /* In passgrp.c */ + iterate_getsmbgrpuid, /* In passgrp.c */ + iterate_getsmbgrprid, /* In passgrp.c */ + getsmbfilegrpent, +}; + +struct passgrp_ops *file_initialise_password_grp(void) +{ + return &file_ops; +} + +#else + /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */ + void smbpass_dummy_function(void) { } /* stop some compilers complaining */ +#endif /* USE_SMBPASS_DB */ -- cgit