1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-14 20:23:54 +03:00

Preliminary merge of winbind into HEAD. Note that this compiles and links

but I haven't actually run it yet so it probably doesn't work.  (-:
This commit is contained in:
Tim Potter
-
parent 2e20734474
commit 59f95416b6
15 changed files with 2762 additions and 1723 deletions

View File

@@ -122,7 +122,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
libsmb/passchange.o libsmb/unexpected.o $(RPC_PARSE_OBJ1)
LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
rpc_client/cli_pipe.o
rpc_client/cli_pipe.o nsswitch/winbindd_glue.o
RPC_SERVER_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o \
rpc_server/srv_lsa_hnd.o rpc_server/srv_netlog.o rpc_server/srv_netlog_nt.o \
@@ -145,11 +145,11 @@ RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_net.o \
rpc_parse/parse_creds.o
RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
rpc_client/cli_lsarpc.o rpc_client/cli_connect.o \
rpc_client/cli_use.o rpc_client/cli_login.o \
rpc_client/cli_spoolss_notify.o rpc_client/ncacn_np_use.o \
lib/util_list.o
#RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
# rpc_client/cli_lsarpc.o rpc_client/cli_connect.o \
# rpc_client/cli_use.o rpc_client/cli_login.o \
# rpc_client/cli_spoolss_notify.o rpc_client/ncacn_np_use.o \
# lib/util_list.o
LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
@@ -351,6 +351,9 @@ PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
PAM_SMBPASS_PICOOBJ = $(PAM_SMBPASS_OBJ_0:.o=.po)
NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
NSS_OBJ = $(NSS_OBJ_0:.o=.po)
WINBINDD_OBJ1 = \
nsswitch/winbindd.o \
nsswitch/winbindd_user.o \
@@ -358,13 +361,14 @@ WINBINDD_OBJ1 = \
nsswitch/winbindd_idmap.o \
nsswitch/winbindd_util.o \
nsswitch/winbindd_cache.o \
nsswitch/winbindd_pam.o
nsswitch/winbindd_pam.o \
nsswitch/winbindd_sid.o \
nsswitch/winbindd_misc.o
WINBINDD_OBJ = \
$(WINBINDD_OBJ1) \
$(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(STUB_UID_OBJ) \
$(WINBINDD_OBJ1) $(NOPROTO_OBJ) $(PASSDB_OBJ) \
$(LIBNMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
$(NSSWINS_OBJ) $(SIDDB_OBJ) $(LIBSMB_OBJ)
$(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) $(GROUPDB_OBJ)
WBINFO_OBJ = nsswitch/wbinfo.o
@@ -372,10 +376,6 @@ WINBIND_NSS_OBJ = nsswitch/winbind_nss.o nsswitch/wb_common.o
WINBIND_NSS_PICOBJS = $(WINBIND_NSS_OBJ:.o=.po)
NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
NSS_OBJ = $(NSS_OBJ_0:.o=.po)
######################################################################
# now the rules...
######################################################################
@@ -623,8 +623,8 @@ bin/wbinfo: $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) $(UBIQX_OBJ) bi
@$(LINK) -o $@ $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) \
$(UBIQX_OBJ) $(LIBS)
nsswitch: nsswitch/libnss_wins.so nsswitch/pam_winbind.so \
nsswitch/libnss_winbind.so bin/wbinfo
nsswitch: nsswitch/pam_winbind.so nsswitch/libnss_winbind.so bin/winbindd \
bin/wbinfo
bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ)
@echo "Linking shared library $@"

View File

@@ -1649,4 +1649,12 @@ typedef struct user_struct
#include "nsswitch/winbindd_nss.h"
#include "smb_acls.h"
/* Used by winbindd_glue functions */
typedef struct {
struct cli_state *cli;
POLICY_HND handle;
TALLOC_CTX *mem_ctx;
} CLI_POLICY_HND;
#endif /* _SMB_H */

View File

@@ -1282,24 +1282,3 @@ char *string_truncate(char *s, int length)
}
return s;
}
/* Parse a string of the form DOMAIN/user into a domain and a user */
void parse_domain_user(char *domuser, fstring domain, fstring user)
{
char *p;
char *sep = lp_winbind_separator();
if (!sep) sep = "\\";
p = strchr(domuser,*sep);
if (!p) p = strchr(domuser,'\\');
if (!p) {
fstrcpy(domain,"");
fstrcpy(user, domuser);
return;
}
fstrcpy(user, p+1);
fstrcpy(domain, domuser);
domain[PTR_DIFF(p, domuser)] = 0;
strupper(domain);
}

View File

@@ -25,6 +25,28 @@
#include "includes.h"
/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
form DOMAIN/user into a domain and a user */
static void parse_domain_user(char *domuser, fstring domain, fstring user)
{
char *p;
char *sep = lp_winbind_separator();
if (!sep) sep = "\\";
p = strchr(domuser,*sep);
if (!p) p = strchr(domuser,'\\');
if (!p) {
fstrcpy(domain,"");
fstrcpy(user, domuser);
return;
}
fstrcpy(user, p+1);
fstrcpy(domain, domuser);
domain[PTR_DIFF(p, domuser)] = 0;
strupper(domain);
}
/* Call winbindd to convert a name to a sid */
BOOL winbind_lookup_name(const char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)

View File

@@ -169,6 +169,7 @@ int write_sock(void *buffer, int count)
while(nwritten < count) {
struct timeval tv;
fd_set r_fds;
int selret;
/* Catch pipe close on other end by checking if a read()
call would not block by calling select(). */
@@ -177,8 +178,8 @@ int write_sock(void *buffer, int count)
FD_SET(established_socket, &r_fds);
ZERO_STRUCT(tv);
if (select(established_socket + 1, &r_fds,
NULL, NULL, &tv) == -1) {
if ((selret = select(established_socket + 1, &r_fds,
NULL, NULL, &tv)) == -1) {
close_sock();
return -1; /* Select error */
}

View File

@@ -29,16 +29,6 @@
#include <config.h>
#ifdef RELIANTUNIX
/*
* <unistd.h> has to be included before any other to get
* large file support on Reliant UNIX. Yes, it's broken :-).
*/
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif /* RELIANTUNIX */
#include <stdio.h>
#ifdef HAVE_STDLIB_H
@@ -173,13 +163,4 @@ typedef int BOOL;
/* zero a structure given a pointer to the structure */
#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
#ifndef S_IFSOCK
#define S_IFSOCK S_IFIFO
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK)
#endif
#endif

View File

@@ -23,17 +23,29 @@
#include "winbindd.h"
pstring servicesf = CONFIGFILE;
/* List of all connected clients */
static struct winbindd_cli_state *client_list;
struct winbindd_cli_state *client_list;
static int num_clients;
/* Reload configuration */
static BOOL reload_services_file(void)
static BOOL reload_services_file(BOOL test)
{
pstring servicesf = CONFIGFILE;
BOOL ret;
if (lp_loaded()) {
pstring fname;
pstrcpy(fname,lp_configfile());
if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) {
pstrcpy(servicesf,fname);
test = False;
}
}
reopen_logs();
ret = lp_load(servicesf,False,False,True);
@@ -43,26 +55,33 @@ static BOOL reload_services_file(void)
return(ret);
}
/* Print client information */
static void do_print_client_info(void)
void winbindd_dump_status(void)
{
struct winbindd_cli_state *client;
int i;
struct winbindd_cli_state *tmp;
if (client_list == NULL) {
DEBUG(0, ("no clients in list\n"));
return;
DEBUG(0, ("Global status for winbindd:\n"));
/* Print client state information */
DEBUG(0, ("\t%d clients currently active\n", num_clients));
if (DEBUGLEVEL >= 2) {
DEBUG(2, ("\tclient list:\n"));
for(tmp = client_list; tmp; tmp = tmp->next) {
DEBUG(2, ("\t\tpid %d, sock %d, rbl %d, wbl %d\n",
tmp->pid, tmp->sock, tmp->read_buf_len,
tmp->write_buf_len));
}
}
}
DEBUG(0, ("client list is:\n"));
/* Print winbindd status to log file */
for (client = client_list, i = 0; client; client = client->next) {
DEBUG(0, ("client %3d: pid = %5d fd = %d read = %4d write = %4d\n",
i, client->pid, client->sock, client->read_buf_len,
client->write_buf_len));
i++;
}
static void do_print_winbindd_status(void)
{
winbindd_dump_status();
winbindd_idmap_dump_status();
winbindd_cache_dump_status();
}
/* Flush client cache */
@@ -82,21 +101,28 @@ static void termination_handler(int signum)
/* Remove socket file */
slprintf(path, sizeof(path)-1, "%s/%s",
snprintf(path, sizeof(path), "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path);
exit(0);
}
static BOOL print_client_info;
static BOOL print_winbindd_status;
static BOOL flush_cache;
static void sigusr1_handler(int signum)
{
BlockSignals(True, SIGUSR1);
print_winbindd_status = True;
BlockSignals(False, SIGUSR1);
}
static BOOL do_sighup;
static void sighup_handler(int signum)
{
BlockSignals(True, SIGHUP);
flush_cache = True;
do_sighup = True;
BlockSignals(False, SIGHUP);
}
@@ -120,14 +146,14 @@ static int create_sock(void)
if (mkdir(WINBINDD_SOCKET_DIR, 0755) == -1) {
DEBUG(0, ("error creating socket directory %s: %s\n",
WINBINDD_SOCKET_DIR, sys_errlist[errno]));
WINBINDD_SOCKET_DIR, strerror(errno)));
return -1;
}
} else {
DEBUG(0, ("lstat failed on socket directory %s: %s\n",
WINBINDD_SOCKET_DIR, sys_errlist[errno]));
WINBINDD_SOCKET_DIR, strerror(errno)));
return -1;
}
@@ -159,7 +185,7 @@ static int create_sock(void)
return -1;
}
slprintf(path, sizeof(path)-1, "%s/%s",
snprintf(path, sizeof(path), "%s/%s",
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
unlink(path);
@@ -170,7 +196,7 @@ static int create_sock(void)
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
DEBUG(0, ("bind failed on winbind socket %s: %s\n",
path,
sys_errlist[errno]));
strerror(errno)));
close(sock);
return -1;
}
@@ -178,7 +204,7 @@ static int create_sock(void)
if (listen(sock, 5) == -1) {
DEBUG(0, ("listen failed on winbind socket %s: %s\n",
path,
sys_errlist[errno]));
strerror(errno)));
close(sock);
return -1;
}
@@ -190,74 +216,91 @@ static int create_sock(void)
return sock;
}
struct dispatch_table {
enum winbindd_cmd cmd;
enum winbindd_result (*fn)(struct winbindd_cli_state *state);
};
static struct dispatch_table dispatch_table[] = {
/* User functions */
{ WINBINDD_GETPWNAM_FROM_USER, winbindd_getpwnam_from_user },
{ WINBINDD_GETPWNAM_FROM_UID, winbindd_getpwnam_from_uid },
{ WINBINDD_SETPWENT, winbindd_setpwent },
{ WINBINDD_ENDPWENT, winbindd_endpwent },
{ WINBINDD_GETPWENT, winbindd_getpwent },
{ WINBINDD_GETGROUPS, winbindd_getgroups },
/* Group functions */
{ WINBINDD_GETGRNAM_FROM_GROUP, winbindd_getgrnam_from_group },
{ WINBINDD_GETGRNAM_FROM_GID, winbindd_getgrnam_from_gid },
{ WINBINDD_SETGRENT, winbindd_setgrent },
{ WINBINDD_ENDGRENT, winbindd_endgrent },
{ WINBINDD_GETGRENT, winbindd_getgrent },
/* PAM auth functions */
{ WINBINDD_PAM_AUTH, winbindd_pam_auth },
{ WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok },
/* Enumeration functions */
{ WINBINDD_LIST_USERS, winbindd_list_users },
{ WINBINDD_LIST_GROUPS, winbindd_list_groups },
{ WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains },
/* SID related functions */
{ WINBINDD_LOOKUPSID, winbindd_lookupsid },
{ WINBINDD_LOOKUPNAME, winbindd_lookupname },
/* S*RS related functions */
{ WINBINDD_SID_TO_UID, winbindd_sid_to_uid },
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid },
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid },
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid },
/* Miscellaneous */
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct },
/* End of list */
{ WINBINDD_NUM_CMDS, NULL }
};
static void process_request(struct winbindd_cli_state *state)
{
/* Process command */
struct dispatch_table *table = dispatch_table;
/* Free response data - we may be interrupted and receive another
command before being able to send this data off. */
safe_free(state->response.extra_data);
ZERO_STRUCT(state->response);
state->response.result = WINBINDD_ERROR;
state->response.length = sizeof(struct winbindd_response);
DEBUG(3,("processing command %s from pid %d\n",
winbindd_cmd_to_string(state->request.cmd), state->pid));
/* Process command */
if (!server_state.lsa_handle_open) return;
switch(state->request.cmd) {
/* User functions */
case WINBINDD_GETPWNAM_FROM_USER:
state->response.result = winbindd_getpwnam_from_user(state);
for (table = dispatch_table; table->fn; table++) {
if (state->request.cmd == table->cmd) {
state->response.result = table->fn(state);
break;
}
}
case WINBINDD_GETPWNAM_FROM_UID:
state->response.result = winbindd_getpwnam_from_uid(state);
break;
/* In case extra data pointer is NULL */
case WINBINDD_SETPWENT:
state->response.result = winbindd_setpwent(state);
break;
case WINBINDD_ENDPWENT:
state->response.result = winbindd_endpwent(state);
break;
case WINBINDD_GETPWENT:
state->response.result = winbindd_getpwent(state);
break;
/* Group functions */
case WINBINDD_GETGRNAM_FROM_GROUP:
state->response.result = winbindd_getgrnam_from_group(state);
break;
case WINBINDD_GETGRNAM_FROM_GID:
state->response.result = winbindd_getgrnam_from_gid(state);
break;
case WINBINDD_SETGRENT:
state->response.result = winbindd_setgrent(state);
break;
case WINBINDD_ENDGRENT:
state->response.result = winbindd_endgrent(state);
break;
case WINBINDD_GETGRENT:
state->response.result = winbindd_getgrent(state);
break;
/* pam auth functions */
case WINBINDD_PAM_AUTH:
state->response.result = winbindd_pam_auth(state);
break;
/* Oops */
default:
DEBUG(0, ("oops - unknown winbindd command %d\n", state->request.cmd));
break;
if (!state->response.extra_data) {
state->response.length = sizeof(struct winbindd_response);
}
}
@@ -294,6 +337,7 @@ static void new_connection(int accept_sock)
/* Add to connection list */
DLIST_ADD(client_list, state);
num_clients++;
}
/* Remove a client connection from client connection list */
@@ -313,7 +357,8 @@ static void remove_client(struct winbindd_cli_state *state)
free_getent_state(state->getpwent_state);
free_getent_state(state->getgrent_state);
/* Free any extra data */
/* We may have some extra data that was not freed if the
client was killed unexpectedly */
safe_free(state->response.extra_data);
@@ -321,6 +366,7 @@ static void remove_client(struct winbindd_cli_state *state)
DLIST_REMOVE(client_list, state);
free(state);
num_clients--;
}
}
@@ -337,7 +383,7 @@ static void process_packet(struct winbindd_cli_state *state)
/* Update client state */
state->read_buf_len = 0;
state->write_buf_len = sizeof(state->response);
state->write_buf_len = sizeof(struct winbindd_response);
}
/* Read some data from a client connection */
@@ -356,7 +402,7 @@ static void client_read(struct winbindd_cli_state *state)
if (n == -1 || n == 0) {
DEBUG(5,("read failed on sock %d, pid %d: %s\n",
state->sock, state->pid,
(n == -1) ? sys_errlist[errno] : "EOF"));
(n == -1) ? strerror(errno) : "EOF"));
state->finished = True;
return;
@@ -372,43 +418,48 @@ static void client_read(struct winbindd_cli_state *state)
static void client_write(struct winbindd_cli_state *state)
{
char *data;
int n;
int num_written;
/* Write data */
/* Write some data */
if (state->write_extra_data) {
/* Write extra data */
data = (char *)state->response.extra_data +
state->response.length - sizeof(struct winbindd_response) -
state->write_buf_len;
} else {
if (!state->write_extra_data) {
/* Write response structure */
data = (char *)&state->response + sizeof(state->response) -
state->write_buf_len;
} else {
/* Write extra data */
data = (char *)state->response.extra_data +
state->response.length -
sizeof(struct winbindd_response) -
state->write_buf_len;
}
n = write(state->sock, data, state->write_buf_len);
num_written = write(state->sock, data, state->write_buf_len);
/* Write failed, kill cilent */
if (n == -1 || n == 0) {
if (num_written == -1 || num_written == 0) {
DEBUG(3,("write failed on sock %d, pid %d: %s\n",
state->sock, state->pid,
(n == -1) ? sys_errlist[errno] : "EOF"));
(num_written == -1) ? strerror(errno) : "EOF"));
state->finished = True;
safe_free(state->response.extra_data);
state->response.extra_data = NULL;
return;
}
/* Update client state */
state->write_buf_len -= n;
state->write_buf_len -= num_written;
/* Have we written all data? */
@@ -416,27 +467,26 @@ static void client_write(struct winbindd_cli_state *state)
/* Take care of extra data */
if (state->response.length > sizeof(struct winbindd_response)) {
if (state->write_extra_data) {
/* Already written extra data - free it */
safe_free(state->response.extra_data);
state->response.extra_data = NULL;
state->write_extra_data = False;
} else {
} else if (state->response.length >
sizeof(struct winbindd_response)) {
/* Start writing extra data */
state->write_buf_len = state->response.length -
state->write_buf_len =
state->response.length -
sizeof(struct winbindd_response);
state->write_extra_data = True;
}
}
}
}
/* Process incoming clients on accept_sock. We use a tricky non-blocking,
non-forking, non-threaded model which allows us to handle many
@@ -453,8 +503,13 @@ static void process_loop(int accept_sock)
int maxfd = accept_sock, selret;
struct timeval timeout;
/* do any connection establishment that is needed */
establish_connections();
/* Free up temporary memory */
lp_talloc_free();
/* Do any connection establishment that is needed */
establish_connections(False); /* Honour timeout */
/* Initialise fd lists for select() */
@@ -470,7 +525,9 @@ static void process_loop(int accept_sock)
state = client_list;
while (state) {
/* Dispose of client connection if it is marked as finished */
/* Dispose of client connection if it is marked as
finished */
if (state->finished) {
struct winbindd_cli_state *next = state->next;
@@ -501,15 +558,25 @@ static void process_loop(int accept_sock)
/* Check signal handling things */
if (flush_cache) {
if (do_sighup) {
/* Flush winbindd cache */
do_flush_caches();
reload_services_file();
flush_cache = False;
reload_services_file(True);
/* Close and re-open all connections. This will also
refresh the trusted domains list */
winbindd_kill_all_connections();
establish_connections(True); /* Force re-establish */
do_sighup = False;
}
if (print_client_info) {
do_print_client_info();
print_client_info = False;
if (print_winbindd_status) {
do_print_winbindd_status();
print_winbindd_status = False;
}
/* Call select */
@@ -546,9 +613,11 @@ static void process_loop(int accept_sock)
client_read(state);
/* A request packet might be complete */
/* A request packet might be
complete */
if (state->read_buf_len == sizeof(state->request)) {
if (state->read_buf_len ==
sizeof(state->request)) {
process_packet(state);
}
}
@@ -573,21 +642,42 @@ int main(int argc, char **argv)
extern pstring debugf;
int accept_sock;
BOOL interactive = False;
int opt;
int opt, new_debuglevel = -1;
while ((opt = getopt(argc, argv, "i")) != EOF) {
/* Set environment variable so we don't recursively call ourselves.
This may also be useful interactively. */
SETENV(WINBINDD_DONT_ENV, "1", 1);
/* Initialise samba/rpc client stuff */
while ((opt = getopt(argc, argv, "id:s:")) != EOF) {
switch (opt) {
/* Don't become a daemon */
case 'i':
interactive = True;
break;
/* Run with specified debug level */
case 'd':
new_debuglevel = atoi(optarg);
break;
/* Load a different smb.conf file */
case 's':
pstrcpy(servicesf,optarg);
break;
default:
printf("Unknown option %c (%d)\n", (char)opt, opt);
printf("Unknown option %c\n", (char)opt);
exit(1);
}
}
/* Initialise samba/rpc client stuff */
slprintf(debugf, sizeof(debugf)-1, "%s/log.winbindd", LOGFILEBASE);
snprintf(debugf, sizeof(debugf), "%s/log.winbindd", LOGFILEBASE);
setup_logging("winbindd", interactive);
reopen_logs();
@@ -603,16 +693,22 @@ int main(int argc, char **argv)
TimeInit();
charset_initialise();
codepage_initialise(lp_client_code_page());
if (!lp_load(CONFIGFILE, True, False, False)) {
if (!reload_services_file(False)) {
DEBUG(0, ("error opening config file\n"));
exit(1);
}
if (new_debuglevel != -1) {
DEBUGLEVEL = new_debuglevel;
}
codepage_initialise(lp_client_code_page());
if (!interactive) {
become_daemon();
}
load_interfaces();
secrets_init();
@@ -620,6 +716,7 @@ int main(int argc, char **argv)
ZERO_STRUCT(server_state);
/* Winbind daemon initialisation */
if (!winbindd_param_init()) {
return 1;
}
@@ -630,6 +727,15 @@ int main(int argc, char **argv)
winbindd_cache_init();
/* Unblock all signals we are interested in as they may have been
blocked by the parent process. */
BlockSignals(False, SIGINT);
BlockSignals(False, SIGQUIT);
BlockSignals(False, SIGTERM);
BlockSignals(False, SIGUSR1);
BlockSignals(False, SIGHUP);
/* Setup signal handlers */
CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
@@ -638,6 +744,7 @@ int main(int argc, char **argv)
CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
CatchSignal(SIGUSR1, sigusr1_handler); /* Debugging sigs */
CatchSignal(SIGHUP, sighup_handler);
/* Create UNIX domain socket */

View File

@@ -49,12 +49,23 @@ struct winbindd_cli_state {
struct getent_state *getgrent_state; /* State for getgrent() */
};
/* State between get{pw,gr}ent() calls */
struct getent_state {
struct getent_state *prev, *next;
struct acct_info *sam_entries;
void *sam_entries;
uint32 sam_entry_index, num_sam_entries;
uint32 dispinfo_ndx;
BOOL got_all_sam_entries, got_sam_entries;
struct winbindd_domain *domain;
BOOL got_sam_entries;
};
/* Storage for cached getpwent() user entries */
struct getpwent_user {
fstring name; /* Account name */
fstring gecos; /* User information */
uint32 user_rid, group_rid; /* NT user and group rids */
};
/* Server state structure */
@@ -68,7 +79,7 @@ struct winbindd_state {
gid_t gid_low, gid_high; /* Range of gids to allocate */
/* Cached handle to lsa pipe */
POLICY_HND lsa_handle;
CLI_POLICY_HND lsa_handle;
BOOL lsa_handle_open;
BOOL pwdb_initialised;
};
@@ -88,8 +99,10 @@ struct winbindd_domain {
BOOL got_domain_info; /* Got controller and sid */
/* Cached handles to samr pipe */
POLICY_HND sam_handle, sam_dom_handle;
CLI_POLICY_HND sam_handle, sam_dom_handle;
BOOL sam_handle_open, sam_dom_handle_open;
time_t last_check;
struct winbindd_domain *prev, *next; /* Linked list info */
};
@@ -99,8 +112,23 @@ extern struct winbindd_domain *domain_list; /* List of domains we know */
#include "winbindd_proto.h"
#include "rpc_parse.h"
#include "rpc_client.h"
#define WINBINDD_ESTABLISH_LOOP 30
#define DOM_SEQUENCE_NONE ((uint32)-1)
/* SETENV */
#if HAVE_SETENV
#define SETENV(name, value, overwrite) setenv(name,value,overwrite)
#elif HAVE_PUTENV
#define SETENV(name, value, overwrite) \
{ \
fstring envvar; \
slprintf(envvar, sizeof(fstring), "%s=%s", name, value); \
putenv(envvar); \
}
#else
#define SETENV(name, value, overwrite) ;
#endif
#endif /* _WINBINDD_H */

View File

@@ -38,10 +38,10 @@ struct cache_rec {
void winbindd_cache_init(void)
{
/* Open tdb cache */
unlink(lock_path("winbindd_cache.tdb"));
if (!(cache_tdb = tdb_open(lock_path("winbindd_cache.tdb"), 0,
TDB_NOLOCK,
O_RDWR | O_CREAT, 0600))) {
TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC,
0600))) {
DEBUG(0, ("Unable to open tdb cache - user and group caching "
"disabled\n"));
}
@@ -55,8 +55,7 @@ static uint32 cached_sequence_number(char *domain_name)
struct cache_rec rec;
time_t t = time(NULL);
slprintf(keystr, sizeof(keystr)-1, "CACHESEQ/%s", domain_name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
dbuf = tdb_fetch_by_string(cache_tdb, keystr);
if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
goto refetch;
@@ -65,7 +64,7 @@ static uint32 cached_sequence_number(char *domain_name)
free(dbuf.dptr);
if (t < (rec.mod_time + lp_winbind_cache_time())) {
DEBUG(4,("cached sequence number for %s is %u\n",
DEBUG(3,("cached sequence number for %s is %u\n",
domain_name, (unsigned)rec.seq_num));
return rec.seq_num;
}
@@ -82,54 +81,56 @@ static uint32 cached_sequence_number(char *domain_name)
static BOOL cache_domain_expired(char *domain_name, uint32 seq_num)
{
if (cached_sequence_number(domain_name) != seq_num) {
DEBUG(4,("seq %u for %s has expired\n", (unsigned)seq_num, domain_name));
DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
domain_name));
return True;
}
return False;
}
static void set_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
static void set_cache_sequence_number(char *domain_name, char *cache_type,
char *subkey)
{
fstring keystr;
slprintf(keystr,sizeof(keystr)-1,"CACHESEQ %s/%s/%s",
snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
domain_name, cache_type, subkey?subkey:"");
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
}
static uint32 get_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
static uint32 get_cache_sequence_number(char *domain_name, char *cache_type,
char *subkey)
{
fstring keystr;
uint32 seq_num;
slprintf(keystr,sizeof(keystr)-1,"CACHESEQ %s/%s/%s",
snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
domain_name, cache_type, subkey?subkey:"");
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
DEBUG(4,("%s is %u\n", keystr, (unsigned)seq_num));
DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
return seq_num;
}
/* Fill the user or group cache with supplied data */
static void fill_cache(char *domain_name, char *cache_type,
struct acct_info *sam_entries,
int num_sam_entries)
static void store_cache(char *domain_name, char *cache_type,
void *sam_entries, int buflen)
{
fstring keystr;
if (lp_winbind_cache_time() == 0) return;
/* Error check */
if (!sam_entries || (num_sam_entries == 0)) return;
DEBUG(4, ("filling %s cache for domain %s with %d entries\n",
cache_type, domain_name, num_sam_entries));
if (!sam_entries || buflen == 0) return;
/* Store data as a mega-huge chunk in the tdb */
slprintf(keystr, sizeof(keystr)-1, "%s CACHE DATA/%s", cache_type,
snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
domain_name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
tdb_store_by_string(cache_tdb, keystr,
sam_entries, sizeof(struct acct_info) * num_sam_entries);
tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
/* Stamp cache with current seq number */
set_cache_sequence_number(domain_name, cache_type, NULL);
@@ -137,61 +138,76 @@ static void fill_cache(char *domain_name, char *cache_type,
/* Fill the user cache with supplied data */
void winbindd_fill_user_cache(char *domain_name,
struct acct_info *sam_entries,
void winbindd_store_user_cache(char *domain,
struct getpwent_user *sam_entries,
int num_sam_entries)
{
fill_cache(domain_name, CACHE_TYPE_USER, sam_entries, num_sam_entries);
DEBUG(3, ("storing user cache %s/%d entries\n", domain,
num_sam_entries));
store_cache(domain, CACHE_TYPE_USER, sam_entries,
num_sam_entries * sizeof(struct getpwent_user));
}
/* Fill the group cache with supplied data */
void winbindd_fill_group_cache(char *domain_name,
void winbindd_store_group_cache(char *domain,
struct acct_info *sam_entries,
int num_sam_entries)
{
fill_cache(domain_name, CACHE_TYPE_GROUP, sam_entries, num_sam_entries);
DEBUG(0, ("storing group cache %s/%d entries\n", domain,
num_sam_entries));
store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
num_sam_entries * sizeof(struct acct_info));
}
static void fill_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
static void store_cache_entry(char *domain, char *cache_type, char *name,
void *buf, int len)
{
fstring keystr;
/* Create key for store */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s", cache_type, domain, name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
DEBUG(4, ("filling cache entry %s\n", keystr));
snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
/* Store it */
tdb_store_by_string(cache_tdb, keystr, buf, len);
}
/* Fill a user info cache entry */
void winbindd_fill_user_cache_entry(char *domain, char *user_name,
void winbindd_store_user_cache_entry(char *domain, char *user_name,
struct winbindd_pw *pw)
{
if (lp_winbind_cache_time() == 0) return;
fill_cache_entry(domain, CACHE_TYPE_USER, user_name, pw, sizeof(struct winbindd_pw));
store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
sizeof(struct winbindd_pw));
set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
}
/* Fill a user uid cache entry */
void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
struct winbindd_pw *pw)
{
fstring uidstr;
if (lp_winbind_cache_time() == 0) return;
slprintf(uidstr, sizeof(uidstr)-1, "#%u", (unsigned)uid);
fill_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
DEBUG(3, ("storing uid cache entry %s/%s\n", domain, uidstr));
store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
sizeof(struct winbindd_pw));
set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
}
/* Fill a group info cache entry */
void winbindd_fill_group_cache_entry(char *domain, char *group_name,
void winbindd_store_group_cache_entry(char *domain, char *group_name,
struct winbindd_gr *gr, void *extra_data,
int extra_data_len)
{
@@ -199,35 +215,47 @@ void winbindd_fill_group_cache_entry(char *domain, char *group_name,
if (lp_winbind_cache_time() == 0) return;
DEBUG(3, ("storing group cache entry %s/%s\n", domain, group_name));
/* Fill group data */
fill_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr, sizeof(struct winbindd_gr));
store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
sizeof(struct winbindd_gr));
/* Fill extra data */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, group_name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
domain, group_name);
tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
}
/* Fill a group info cache entry */
void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
struct winbindd_gr *gr, void *extra_data,
int extra_data_len)
{
fstring keystr;
fstring gidstr;
slprintf(gidstr, sizeof(gidstr)-1, "#%u", (unsigned)gid);
snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
if (lp_winbind_cache_time() == 0) return;
DEBUG(3, ("storing gid cache entry %s/%s\n", domain, gidstr));
/* Fill group data */
fill_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr, sizeof(struct winbindd_gr));
store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
sizeof(struct winbindd_gr));
/* Fill extra data */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain, gidstr);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
domain, gidstr);
tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
@@ -235,7 +263,7 @@ void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
/* Fetch some cached user or group data */
static BOOL fetch_cache(char *domain_name, char *cache_type,
struct acct_info **sam_entries, int *num_sam_entries)
void **sam_entries, int *buflen)
{
TDB_DATA data;
fstring keystr;
@@ -243,20 +271,21 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
if (lp_winbind_cache_time() == 0) return False;
/* Parameter check */
if (!sam_entries || !num_sam_entries) {
if (!sam_entries || !buflen) {
return False;
}
/* Check cache data is current */
if (cache_domain_expired(domain_name,
get_cache_sequence_number(domain_name, cache_type, NULL))) {
get_cache_sequence_number(domain_name,
cache_type,
NULL))) {
return False;
}
/* Create key */
slprintf(keystr, sizeof(keystr)-1, "%s CACHE DATA/%s", cache_type,
snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
domain_name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
/* Fetch cache information */
data = tdb_fetch_by_string(cache_tdb, keystr);
@@ -268,10 +297,7 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
be freed by the end{pw,gr}ent() function. */
*sam_entries = (struct acct_info *)data.dptr;
*num_sam_entries = data.dsize / sizeof(struct acct_info);
DEBUG(4, ("fetched %d cached %s entries for domain %s\n",
*num_sam_entries, cache_type, domain_name));
*buflen = data.dsize;
return True;
}
@@ -280,11 +306,21 @@ static BOOL fetch_cache(char *domain_name, char *cache_type,
entries, or the cached information has expired for the domain. */
BOOL winbindd_fetch_user_cache(char *domain_name,
struct acct_info **sam_entries,
struct getpwent_user **sam_entries,
int *num_entries)
{
return fetch_cache(domain_name, CACHE_TYPE_USER, sam_entries,
num_entries);
BOOL result;
int buflen;
result = fetch_cache(domain_name, CACHE_TYPE_USER,
(void **)sam_entries, &buflen);
*num_entries = buflen / sizeof(struct getpwent_user);
DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
domain_name));
return result;
}
/* Return cached entries for a domain. Return false if there are no cached
@@ -294,25 +330,33 @@ BOOL winbindd_fetch_group_cache(char *domain_name,
struct acct_info **sam_entries,
int *num_entries)
{
return fetch_cache(domain_name, CACHE_TYPE_GROUP, sam_entries,
num_entries);
BOOL result;
int buflen;
result = fetch_cache(domain_name, CACHE_TYPE_GROUP,
(void **)sam_entries, &buflen);
*num_entries = buflen / sizeof(struct acct_info);
DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
domain_name));
return result;
}
static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name, void *buf, int len)
static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name,
void *buf, int len)
{
TDB_DATA data;
fstring keystr;
/* Create key for lookup */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s", cache_type, domain, name);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
/* Look up cache entry */
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
DEBUG(4, ("returning cached entry for %s\\%s\n", domain, name));
/* Copy found entry into buffer */
memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
free(data.dptr);
@@ -327,10 +371,12 @@ BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
if (lp_winbind_cache_time() == 0) return False;
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, user);
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
user);
if (cache_domain_expired(domain_name, seq_num)) return False;
return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw, sizeof(struct winbindd_pw));
return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw,
sizeof(struct winbindd_pw));
}
/* Fetch an individual uid cache entry */
@@ -342,11 +388,13 @@ BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
if (lp_winbind_cache_time() == 0) return False;
slprintf(uidstr, sizeof(uidstr)-1, "#%u", (unsigned)uid);
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER, uidstr);
snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
uidstr);
if (cache_domain_expired(domain_name, seq_num)) return False;
return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw, sizeof(struct winbindd_pw));
return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw,
sizeof(struct winbindd_pw));
}
/* Fetch an individual group cache entry. This function differs from the
@@ -362,15 +410,21 @@ BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
if (lp_winbind_cache_time() == 0) return False;
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, group);
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
group);
if (cache_domain_expired(domain_name, seq_num)) return False;
/* Fetch group data */
if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr, sizeof(struct winbindd_gr))) return False;
if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr,
sizeof(struct winbindd_gr))) {
return False;
}
/* Fetch extra data */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, group);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
domain_name, group);
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
@@ -395,20 +449,24 @@ BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
fstring gidstr;
uint32 seq_num;
slprintf(gidstr, sizeof(gidstr)-1, "#%u", (unsigned)gid);
snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
if (lp_winbind_cache_time() == 0) return False;
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP, gidstr);
seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
gidstr);
if (cache_domain_expired(domain_name, seq_num)) return False;
/* Fetch group data */
if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
gidstr, gr, sizeof(struct winbindd_gr))) return False;
gidstr, gr, sizeof(struct winbindd_gr))) {
return False;
}
/* Fetch extra data */
slprintf(keystr, sizeof(keystr)-1, "%s/%s/%s DATA", CACHE_TYPE_GROUP, domain_name, gidstr);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
domain_name, gidstr);
data = tdb_fetch_by_string(cache_tdb, keystr);
if (!data.dptr) return False;
@@ -425,3 +483,8 @@ void winbindd_flush_cache(void)
tdb_close(cache_tdb);
winbindd_cache_init();
}
/* Print cache status information */
void winbindd_cache_dump_status(void)
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -73,12 +73,11 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, int *id,
{
TDB_DATA data, key;
fstring keystr;
BOOL result;
BOOL result = False;
/* Check if rid is present in database */
slprintf(keystr, sizeof(keystr)-1, "%s/%d", domain_name, rid);
dos_to_unix(keystr, True); /* Convert key to unix-codepage */
slprintf(keystr, sizeof(keystr), "%s/%d", domain_name, rid);
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
@@ -116,7 +115,7 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, int *id,
/* Store new id */
slprintf(keystr2, sizeof(keystr2)-1, "%s %d", isgroup ? "GID" :
slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" :
"UID", *id);
data.dptr = keystr2;
@@ -155,7 +154,7 @@ BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
fstring keystr;
BOOL result = False;
slprintf(keystr, sizeof(keystr)-1, "%s %d", isgroup ? "GID" : "UID", id);
slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id);
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
@@ -177,11 +176,17 @@ BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
if (domain) {
*domain = find_domain_from_name(domain_name);
if (*domain == NULL) {
DEBUG(1, ("unknown domain %s for rid %d\n",
domain_name, the_rid));
result = False;
goto done;
}
}
result = True;
}
done:
free(data.dptr);
}
@@ -211,8 +216,7 @@ BOOL winbindd_idmap_init(void)
/* Open tdb cache */
if (!(idmap_tdb = tdb_open(lock_path("winbindd_idmap.tdb"), 0,
TDB_NOLOCK | TDB_NOMMAP,
O_RDWR | O_CREAT, 0600))) {
TDB_NOLOCK, O_RDWR | O_CREAT, 0600))) {
DEBUG(0, ("Unable to open idmap database\n"));
return False;
}
@@ -235,3 +239,63 @@ BOOL winbindd_idmap_init(void)
return True;
}
/* Dump status information to log file. Display different stuff based on
the debug level:
Debug Level Information Displayed
=================================================================
0 Percentage of [ug]id range allocated
0 High water marks (next allocated ids)
*/
#define DUMP_INFO 0
void winbindd_idmap_dump_status(void)
{
int user_hwm, group_hwm;
DEBUG(0, ("Status for winbindd idmap:\n"));
/* Get current high water marks */
if ((user_hwm = tdb_fetch_int(idmap_tdb, HWM_USER)) == -1) {
DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n"));
}
if ((group_hwm = tdb_fetch_int(idmap_tdb, HWM_GROUP)) == -1) {
DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n"));
}
/* Display next ids to allocate */
if (user_hwm != -1) {
DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm));
}
if (group_hwm != -1) {
DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm));
}
/* Display percentage of id range already allocated. */
if (user_hwm != -1) {
int num_users = user_hwm - server_state.uid_low;
int total_users = server_state.uid_high - server_state.uid_low;
DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n",
num_users * 100 / total_users, num_users,
total_users));
}
if (group_hwm != -1) {
int num_groups = group_hwm - server_state.gid_low;
int total_groups = server_state.gid_high - server_state.gid_low;
DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n",
num_groups * 100 / total_groups, num_groups,
total_groups));
}
/* Display complete mapping of users and groups to rids */
}

View File

@@ -23,6 +23,28 @@
#include "winbindd.h"
/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
form DOMAIN/user into a domain and a user */
static void parse_domain_user(char *domuser, fstring domain, fstring user)
{
char *p;
char *sep = lp_winbind_separator();
if (!sep) sep = "\\";
p = strchr(domuser,*sep);
if (!p) p = strchr(domuser,'\\');
if (!p) {
fstrcpy(domain,"");
fstrcpy(user, domuser);
return;
}
fstrcpy(user, p+1);
fstrcpy(domain, domuser);
domain[PTR_DIFF(p, domuser)] = 0;
strupper(domain);
}
/* Return a password structure from a username. Specify whether cached data
can be returned. */
@@ -31,31 +53,37 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
NET_USER_INFO_3 info3;
uchar ntpw[16];
uchar lmpw[16];
uint8 trust_passwd[16];
uchar trust_passwd[16];
uint32 status;
fstring server;
fstring name_domain, name_user;
extern pstring global_myname;
DEBUG(1,("winbindd_pam_auth user=%s\n",
DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
state->request.data.auth.user));
/* Parse domain and username */
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
parse_domain_user(state->request.data.auth.user, name_domain,
name_user);
/* don't allow the null domain */
if (strcmp(name_domain,"") == 0) return WINBINDD_ERROR;
ZERO_STRUCT(info3);
if (!secrets_fetch_trust_account_password(lp_workgroup(),
trust_passwd, NULL)) {
if (!_get_trust_account_password(lp_workgroup(), trust_passwd, NULL)) {
DEBUG(1, ("could not get trust password for domain %s\n",
name_domain));
return WINBINDD_ERROR;
}
nt_lm_owf_gen(state->request.data.auth.pass, ntpw, lmpw);
slprintf(server, sizeof(server)-1, "\\\\%s", server_state.controller);
slprintf(server, sizeof(server), "\\\\%s", server_state.controller);
#if 0
/* XXX */
status = domain_client_validate_backend(server,
name_user, name_domain,
@@ -64,9 +92,51 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
NULL,
lmpw, sizeof(lmpw),
ntpw, sizeof(ntpw), &info3);
#else
status = NT_STATUS_UNSUCCESSFUL;
#endif
if (status != NT_STATUS_NOPROBLEMO) return WINBINDD_ERROR;
return WINBINDD_OK;
}
/* Change a user password */
enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
{
char *oldpass, *newpass;
fstring domain, user;
uchar nt_oldhash[16];
uchar lm_oldhash[16];
DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
state->request.data.chauthtok.user));
/* Setup crap */
if (state == NULL) return WINBINDD_ERROR;
parse_domain_user(state->request.data.chauthtok.user, domain, user);
oldpass = state->request.data.chauthtok.oldpass;
newpass = state->request.data.chauthtok.newpass;
nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash);
/* Change password */
#if 0
/* XXX */
if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user,
lm_oldhash, nt_oldhash, newpass)) {
DEBUG(0, ("password change failed for user %s/%s\n", domain, user));
return WINBINDD_ERROR;
}
#endif
return WINBINDD_OK;
}

View File

@@ -5,29 +5,30 @@
/*The following definitions come from nsswitch/winbindd.c */
void winbindd_dump_status(void);
int main(int argc, char **argv);
/*The following definitions come from nsswitch/winbindd_cache.c */
void winbindd_cache_init(void);
void winbindd_fill_user_cache(char *domain_name,
void winbindd_store_user_cache(char *domain,
struct getpwent_user *sam_entries,
int num_sam_entries);
void winbindd_store_group_cache(char *domain,
struct acct_info *sam_entries,
int num_sam_entries);
void winbindd_fill_group_cache(char *domain_name,
struct acct_info *sam_entries,
int num_sam_entries);
void winbindd_fill_user_cache_entry(char *domain, char *user_name,
void winbindd_store_user_cache_entry(char *domain, char *user_name,
struct winbindd_pw *pw);
void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
struct winbindd_pw *pw);
void winbindd_fill_group_cache_entry(char *domain, char *group_name,
void winbindd_store_group_cache_entry(char *domain, char *group_name,
struct winbindd_gr *gr, void *extra_data,
int extra_data_len);
void winbindd_fill_gid_cache_entry(char *domain, gid_t gid,
void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
struct winbindd_gr *gr, void *extra_data,
int extra_data_len);
BOOL winbindd_fetch_user_cache(char *domain_name,
struct acct_info **sam_entries,
struct getpwent_user **sam_entries,
int *num_entries);
BOOL winbindd_fetch_group_cache(char *domain_name,
struct acct_info **sam_entries,
@@ -43,15 +44,19 @@ BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
struct winbindd_gr *gr,
void **extra_data, int *extra_data_len);
void winbindd_flush_cache(void);
void winbindd_cache_dump_status(void);
/*The following definitions come from nsswitch/winbindd_group.c */
enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
*state);
enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
*state);
enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_idmap.c */
@@ -66,34 +71,60 @@ BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
struct winbindd_domain **domain);
BOOL winbindd_idmap_init(void);
void winbindd_idmap_dump_status(void);
/*The following definitions come from nsswitch/winbindd_misc.c */
BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd,
time_t *pass_last_set_time);
enum winbindd_result winbindd_check_machine_acct(
struct winbindd_cli_state *state);
enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
*state);
/*The following definitions come from nsswitch/winbindd_pam.c */
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) ;
enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_sid.c */
enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state);
enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state);
enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state);
enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state);
enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state);
enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_user.c */
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state) ;
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state
*state) ;
enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
*state);
enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state);
enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state);
/*The following definitions come from nsswitch/winbindd_util.c */
void debug_conn_state(void);
BOOL domain_handles_open(struct winbindd_domain *domain);
void establish_connections(void) ;
void winbindd_kill_connections(struct winbindd_domain *domain);
void winbindd_kill_all_connections(void);
void establish_connections(BOOL force_reestablish) ;
BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain);
BOOL get_domain_info(struct winbindd_domain *domain);
BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
char *name, DOM_SID *sid,
BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid,
enum SID_NAME_USE *type);
BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
DOM_SID *sid, char *name,
BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name,
enum SID_NAME_USE *type);
BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
uint32 user_rid, SAM_USERINFO_CTR *user_info);
BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain,
uint32 user_rid, uint32 *num_groups,
DOM_GID **user_groups);
BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain,
uint32 group_rid, GROUP_INFO_CTR *info);
BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
@@ -105,9 +136,14 @@ int winbindd_lookup_aliasmem(struct winbindd_domain *domain,
DOM_SID ***sids, char ***names,
enum SID_NAME_USE **name_types);
struct winbindd_domain *find_domain_from_name(char *domain_name);
struct winbindd_domain *find_domain_from_sid(DOM_SID *sid);
void free_getent_state(struct getent_state *state);
BOOL winbindd_param_init(void);
char *winbindd_cmd_to_string(enum winbindd_cmd cmd);
void parse_domain_user(char *domuser, fstring domain, fstring user);
uint32 domain_sequence_number(char *domain_name);
uint32 winbindd_query_dispinfo(struct winbindd_domain *domain,
uint32 *start_ndx, uint16 info_level,
uint32 *num_entries, SAM_DISPINFO_CTR *ctr);
BOOL check_domain_env(char *domain_env, char *domain);
void parse_domain_user(char *domuser, fstring domain, fstring user);
#endif /* _WINBINDD_PROTO_H_ */

View File

@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 2.0
Winbind daemon - user related function
Winbind daemon - user related functions
Copyright (C) Tim Potter 2000
@@ -25,21 +25,32 @@
/* Fill a pwent structure with information we have obtained */
static void winbindd_fill_pwent(struct winbindd_pw *pw, char *name,
uid_t unix_uid, gid_t unix_gid,
char *full_name)
static BOOL winbindd_fill_pwent(char *domain_name, char *name,
uint32 user_rid, uint32 group_rid,
char *full_name, struct winbindd_pw *pw)
{
pstring homedir;
fstring name_domain, name_user;
pstring homedir;
if (!pw || !name) {
return;
return False;
}
/* Fill in uid/gid */
/* Resolve the uid number */
pw->pw_uid = unix_uid;
pw->pw_gid = unix_gid;
if (!winbindd_idmap_get_uid_from_rid(domain_name, user_rid,
&pw->pw_uid)) {
DEBUG(1, ("error getting user id for rid %d\n", user_rid));
return False;
}
/* Resolve the gid number */
if (!winbindd_idmap_get_gid_from_rid(domain_name, group_rid,
&pw->pw_gid)) {
DEBUG(1, ("error getting group id for rid %d\n", group_rid));
return False;
}
/* Username */
@@ -50,43 +61,59 @@ static void winbindd_fill_pwent(struct winbindd_pw *pw, char *name,
safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
/* Home directory and shell - use template config parameters. The
defaults are /tmp for the home directory and /bin/false for shell. */
defaults are /tmp for the home directory and /bin/false for
shell. */
parse_domain_user(name, name_domain, name_user);
pstrcpy(homedir, lp_template_homedir());
/*
* Insist name_user is lowercase, name_domain is uppercase.
* This is a hack. JRA.
*/
strlower(name_user);
strupper(name_domain);
pstring_sub(homedir, "%U", name_user);
pstring_sub(homedir, "%D", name_domain);
safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
safe_strcpy(pw->pw_shell, lp_template_shell(), sizeof(pw->pw_shell) - 1);
safe_strcpy(pw->pw_shell, lp_template_shell(),
sizeof(pw->pw_shell) - 1);
/* Password - set to "x" as we can't generate anything useful here.
Authentication can be done using the pam_ntdom module. */
safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
return True;
}
/* Return a password structure from a username. Specify whether cached data
can be returned. */
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state)
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state
*state)
{
uint32 name_type, user_rid, group_rid;
SAM_USERINFO_CTR user_info;
DOM_SID user_sid;
fstring name_domain, name_user, name, gecos_name;
struct winbindd_domain *domain;
uid_t uid;
gid_t gid;
DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid,
state->request.data.username));
/* Parse domain and username */
parse_domain_user(state->request.data.username, name_domain, name_user);
/* Reject names that don't have a domain - i.e name_domain contains the
entire name. */
parse_domain_user(state->request.data.username, name_domain,
name_user);
/* Reject names that don't have a domain - i.e name_domain contains
the entire name. */
if (strequal(name_domain, "")) {
return WINBINDD_ERROR;
@@ -95,7 +122,12 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *stat
/* Get info for the domain */
if ((domain = find_domain_from_name(name_domain)) == NULL) {
DEBUG(0, ("could not find domain entry for domain %s\n", name_domain));
DEBUG(0, ("could not find domain entry for domain %s\n",
name_domain));
return WINBINDD_ERROR;
}
if (!domain_handles_open(domain)) {
return WINBINDD_ERROR;
}
@@ -108,28 +140,30 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *stat
slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user);
/* Get rid and name type from name */
/* the following costs 1 packet */
if (!winbindd_lookup_sid_by_name(domain, name, &user_sid, &name_type)) {
/* Get rid and name type from name. The following costs 1 packet */
if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) {
DEBUG(1, ("user '%s' does not exist\n", name_user));
return WINBINDD_ERROR;
}
if (name_type != SID_NAME_USER) {
DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type));
DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
name_type));
return WINBINDD_ERROR;
}
/* Get some user info. Split the user rid from the sid obtained from
the winbind_lookup_by_name() call and use it in a
/* Get some user info. Split the user rid from the sid obtained
from the winbind_lookup_by_name() call and use it in a
winbind_lookup_userinfo() */
sid_split_rid(&user_sid, &user_rid);
/* the following costs 3 packets */
/* The following costs 3 packets */
if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
DEBUG(1, ("pwnam_from_user(): error getting user info for user '%s'\n",
name_user));
DEBUG(1, ("pwnam_from_user(): error getting user info for "
"user '%s'\n", name_user));
return WINBINDD_ERROR;
}
@@ -139,27 +173,15 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *stat
free_samr_userinfo_ctr(&user_info);
/* Resolve the uid number */
if (!winbindd_idmap_get_uid_from_rid(domain->name, user_rid, &uid)) {
DEBUG(1, ("error getting user id for user %s\n", name_user));
return WINBINDD_ERROR;
}
/* Resolve the gid number */
if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
DEBUG(1, ("error getting group id for user %s\n", name_user));
return WINBINDD_ERROR;
}
/* Now take all this information and fill in a passwd structure */
winbindd_fill_pwent(&state->response.data.pw,
state->request.data.username, uid, gid,
gecos_name);
if (!winbindd_fill_pwent(domain->name, state->request.data.username,
user_rid, group_rid, gecos_name,
&state->response.data.pw)) {
return WINBINDD_ERROR;
}
winbindd_fill_user_cache_entry(name_domain, name_user,
winbindd_store_user_cache_entry(name_domain, name_user,
&state->response.data.pw);
return WINBINDD_OK;
@@ -178,28 +200,43 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
SAM_USERINFO_CTR user_info;
gid_t gid;
/* Bug out if the uid isn't in the winbind range */
if ((state->request.data.uid < server_state.uid_low ) ||
(state->request.data.uid > server_state.uid_high)) {
return WINBINDD_ERROR;
}
DEBUG(3, ("[%5d]: getpwuid %d\n", state->pid,
state->request.data.uid));
/* Get rid from uid */
if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid, &user_rid,
&domain)) {
if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid,
&user_rid, &domain)) {
DEBUG(1, ("Could not convert uid %d to rid\n",
state->request.data.uid));
return WINBINDD_ERROR;
}
if (!domain_handles_open(domain)) {
return WINBINDD_ERROR;
}
/* Check for cached uid entry */
if (winbindd_fetch_uid_cache_entry(domain->name, state->request.data.uid,
if (winbindd_fetch_uid_cache_entry(domain->name,
state->request.data.uid,
&state->response.data.pw)) {
return WINBINDD_OK;
}
/* Get name and name type from rid */
sid_copy(&user_sid, &domain->sid);
sid_append_rid(&user_sid, user_rid);
if (!winbindd_lookup_name_by_sid(domain, &user_sid, user_name,
&name_type)) {
if (!winbindd_lookup_name_by_sid(&user_sid, user_name, &name_type)) {
fstring temp;
sid_to_string(temp, &user_sid);
@@ -208,14 +245,15 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
}
if (strcmp("\\", lp_winbind_separator())) {
string_sub(user_name, "\\", lp_winbind_separator(), sizeof(fstring));
string_sub(user_name, "\\", lp_winbind_separator(),
sizeof(fstring));
}
/* Get some user info */
if (!winbindd_lookup_userinfo(domain, user_rid, &user_info)) {
DEBUG(1, ("pwnam_from_uid(): error getting user info for user '%s'\n",
user_name));
DEBUG(1, ("pwnam_from_uid(): error getting user info for "
"user '%s'\n", user_name));
return WINBINDD_ERROR;
}
@@ -234,10 +272,12 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
/* Fill in password structure */
winbindd_fill_pwent(&state->response.data.pw, user_name,
state->request.data.uid, gid, gecos_name);
if (!winbindd_fill_pwent(domain->name, user_name, user_rid, group_rid,
gecos_name, &state->response.data.pw)) {
return WINBINDD_ERROR;
}
winbindd_fill_uid_cache_entry(domain->name, state->request.data.uid,
winbindd_store_uid_cache_entry(domain->name, state->request.data.uid,
&state->response.data.pw);
return WINBINDD_OK;
@@ -253,8 +293,16 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
{
struct winbindd_domain *tmp;
DEBUG(3, ("[%5d]: setpwent\n", state->pid));
if (state == NULL) return WINBINDD_ERROR;
/* Check user has enabled this */
if (!lp_winbind_enum_users()) {
return WINBINDD_ERROR;
}
/* Free old static data if it exists */
if (state->getpwent_state != NULL) {
@@ -270,7 +318,7 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
/* Skip domains other than WINBINDD_DOMAIN environment variable */
if ((strcmp(state->request.domain, "") != 0) &&
(strcmp(state->request.domain, tmp->name) != 0)) {
!check_domain_env(state->request.domain, tmp->name)) {
continue;
}
@@ -297,6 +345,8 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5d]: endpwent\n", state->pid));
if (state == NULL) return WINBINDD_ERROR;
free_getent_state(state->getpwent_state);
@@ -305,110 +355,339 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
/* Get partial list of domain users for a domain. We fill in the sam_entries,
and num_sam_entries fields with domain user information. The dispinfo_ndx
field is incremented to the index of the next user to fetch. Return True if
some users were returned, False otherwise. */
#define MAX_FETCH_SAM_ENTRIES 100
static BOOL get_sam_user_entries(struct getent_state *ent)
{
uint32 status, num_entries;
SAM_DISPINFO_1 info1;
SAM_DISPINFO_CTR ctr;
struct getpwent_user *name_list = NULL;
uint32 group_rid;
if (ent->got_all_sam_entries) {
return False;
}
ZERO_STRUCT(info1);
ZERO_STRUCT(ctr);
ctr.sam.info1 = &info1;
#if 0
/* Look in cache for entries, else get them direct */
if (winbindd_fetch_user_cache(ent->domain->name,
(struct getpwent_user **)
&ent->sam_entries,
&ent->num_sam_entries)) {
return True;
}
#endif
/* For the moment we set the primary group for every user to be the
Domain Users group. There are serious problems with determining
the actual primary group for large domains. This should really
be made into a 'winbind force group' smb.conf parameter or
something like that. */
group_rid = DOMAIN_GROUP_RID_USERS;
if (!domain_handles_open(ent->domain)) {
return WINBINDD_ERROR;
}
/* Free any existing user info */
if (ent->sam_entries) {
free(ent->sam_entries);
ent->sam_entries = NULL;
ent->num_sam_entries = 0;
}
/* Call query_dispinfo to get a list of usernames and user rids */
do {
int i;
num_entries = 0;
status = winbindd_query_dispinfo(ent->domain,
&ent->dispinfo_ndx, 1,
&num_entries, &ctr);
if (num_entries) {
name_list = Realloc(name_list,
sizeof(struct getpwent_user) *
(ent->num_sam_entries +
num_entries));
}
for (i = 0; i < num_entries; i++) {
/* Store account name and gecos */
unistr2_to_ascii(
name_list[ent->num_sam_entries + i].name,
&info1.str[i].uni_acct_name,
sizeof(fstring));
unistr2_to_ascii(
name_list[ent->num_sam_entries + i].gecos,
&info1.str[i].uni_full_name,
sizeof(fstring));
/* User and group ids */
name_list[ent->num_sam_entries + i].user_rid =
info1.sam[i].rid_user;
name_list[ent->num_sam_entries + i].
group_rid = group_rid;
}
ent->num_sam_entries += num_entries;
if (status != STATUS_MORE_ENTRIES) {
break;
}
} while (ent->num_sam_entries < MAX_FETCH_SAM_ENTRIES);
#if 0
/* Fill cache with received entries */
winbindd_store_user_cache(ent->domain->name, ent->sam_entries,
ent->num_sam_entries);
#endif
/* Fill in remaining fields */
ent->sam_entries = name_list;
ent->sam_entry_index = 0;
ent->got_all_sam_entries = (status != STATUS_MORE_ENTRIES);
return ent->num_sam_entries > 0;
}
/* Fetch next passwd entry from ntdom database */
#define MAX_GETPWENT_USERS 500
enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
{
struct getent_state *ent;
struct winbindd_pw *user_list;
int num_users, user_list_ndx = 0, i;
char *sep;
DEBUG(3, ("[%5d]: getpwent\n", state->pid));
if (state == NULL) return WINBINDD_ERROR;
/* Process the current head of the getent_state list */
/* Check user has enabled this */
while(state->getpwent_state != NULL) {
struct getent_state *ent = state->getpwent_state;
/* Get list of user entries for this pipe */
if (!ent->got_sam_entries) {
uint32 status, start_ndx = 0;
/* Look in cache for entries, else get them direct */
if (!winbindd_fetch_user_cache(ent->domain->name,
&ent->sam_entries,
&ent->num_sam_entries)) {
/* Fetch the user entries */
if (!domain_handles_open(ent->domain)) goto cleanup;
do {
status =
samr_enum_dom_users(
&ent->domain->sam_dom_handle, &start_ndx, 0, 0,
0x10000, &ent->sam_entries, &ent->num_sam_entries);
} while (status == STATUS_MORE_ENTRIES);
/* Fill cache with received entries */
winbindd_fill_user_cache(ent->domain->name, ent->sam_entries,
ent->num_sam_entries);
if (!lp_winbind_enum_users()) {
return WINBINDD_ERROR;
}
ent->got_sam_entries = True;
/* Allocate space for returning a chunk of users */
num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
if ((state->response.extra_data =
malloc(num_users * sizeof(struct winbindd_pw))) == NULL) {
return WINBINDD_ERROR;
}
/* Send back a user */
memset(state->response.extra_data, 0, num_users *
sizeof(struct winbindd_pw));
while (ent->sam_entry_index < ent->num_sam_entries) {
enum winbindd_result result;
user_list = (struct winbindd_pw *)state->response.extra_data;
sep = lp_winbind_separator();
if (!(ent = state->getpwent_state)) {
return WINBINDD_ERROR;
}
/* Start sending back users */
for (i = 0; i < num_users; i++) {
struct getpwent_user *name_list = NULL;
fstring domain_user_name;
char *user_name = (ent->sam_entries)
[ent->sam_entry_index].acct_name;
uint32 result;
/* Don't bother with machine accounts */
/* Do we need to fetch another chunk of users? */
if (user_name[strlen(user_name) - 1] == '$') {
if (ent->num_sam_entries == ent->sam_entry_index) {
while(ent && !get_sam_user_entries(ent)) {
struct getent_state *next_ent;
/* Free state information for this domain */
safe_free(ent->sam_entries);
ent->sam_entries = NULL;
next_ent = ent->next;
DLIST_REMOVE(state->getpwent_state, ent);
free(ent);
ent = next_ent;
}
/* No more domains */
if (!ent) break;
}
name_list = ent->sam_entries;
/* Skip machine accounts */
if (name_list[ent->sam_entry_index].
name[strlen(name_list[ent->sam_entry_index].name) - 1]
== '$') {
ent->sam_entry_index++;
continue;
}
/* Prepend domain to name */
/* Lookup user info */
slprintf(domain_user_name, sizeof(domain_user_name) - 1,
"%s%s%s", ent->domain->name, lp_winbind_separator(), user_name);
"%s%s%s", ent->domain->name, sep,
name_list[ent->sam_entry_index].name);
/* Get passwd entry from user name */
fstrcpy(state->request.data.username, domain_user_name);
result = winbindd_getpwnam_from_user(state);
result = winbindd_fill_pwent(
ent->domain->name,
domain_user_name,
name_list[ent->sam_entry_index].user_rid,
name_list[ent->sam_entry_index].group_rid,
name_list[ent->sam_entry_index].gecos,
&user_list[user_list_ndx]);
ent->sam_entry_index++;
/* Return if user lookup worked */
/* Add user to return list */
if (result == WINBINDD_OK) {
return result;
}
if (result) {
/* Try next user */
user_list_ndx++;
state->response.data.num_entries++;
state->response.length +=
sizeof(struct winbindd_pw);
DEBUG(1, ("could not getpwnam_from_user for username %s\n",
} else {
DEBUG(1, ("could not lookup domain user %s\n",
domain_user_name));
}
/* We've exhausted all users for this pipe - close it down and
start on the next one. */
}
cleanup:
/* Out of domains */
/* Free mallocated memory for sam entries. The data stored here
may have been allocated from the cache. */
return (user_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
}
if (ent->sam_entries != NULL) free(ent->sam_entries);
ent->sam_entries = NULL;
/* Free state information for this domain */
/* List domain users without mapping to unix ids */
enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
{
struct getent_state *old_ent;
struct winbindd_domain *domain;
SAM_DISPINFO_CTR ctr;
SAM_DISPINFO_1 info1;
uint32 num_entries = 0, total_entries = 0;
char *extra_data = NULL;
int extra_data_len = 0;
old_ent = state->getpwent_state;
DLIST_REMOVE(state->getpwent_state, state->getpwent_state);
free(old_ent);
}
DEBUG(3, ("[%5d]: list users\n", state->pid));
/* Enumerate over trusted domains */
ctr.sam.info1 = &info1;
for (domain = domain_list; domain; domain = domain->next) {
uint32 status, start_ndx = 0;
/* Skip domains other than WINBINDD_DOMAIN environment
variable */
if ((strcmp(state->request.domain, "") != 0) &&
!check_domain_env(state->request.domain, domain->name)) {
continue;
}
/* Out of pipes so we're done */
if (!domain_handles_open(domain)) {
continue;
}
/* Query display info */
do {
int i;
status = winbindd_query_dispinfo(domain, &start_ndx,
1, &num_entries,
&ctr);
if (num_entries == 0) {
continue;
}
/* Allocate some memory for extra data */
total_entries += num_entries;
extra_data = Realloc(extra_data, sizeof(fstring) *
total_entries);
if (!extra_data) {
return WINBINDD_ERROR;
}
/* Pack user list into extra data fields */
for (i = 0; i < num_entries; i++) {
UNISTR2 *uni_acct_name;
fstring acct_name, name;
/* Convert unistring to ascii */
uni_acct_name = &ctr.sam.info1->str[i].
uni_acct_name;
unistr2_to_ascii(acct_name, uni_acct_name,
sizeof(acct_name) - 1);
slprintf(name, sizeof(name) - 1, "%s%s%s",
domain->name, lp_winbind_separator(),
acct_name);
/* Append to extra data */
memcpy(&extra_data[extra_data_len], name,
strlen(name));
extra_data_len += strlen(name);
extra_data[extra_data_len++] = ',';
}
} while (status == STATUS_MORE_ENTRIES);
}
/* Assign extra_data fields in response structure */
if (extra_data) {
extra_data[extra_data_len - 1] = '\0';
state->response.extra_data = extra_data;
state->response.length += extra_data_len;
}
/* No domains responded but that's still OK so don't return an
error. */
return WINBINDD_OK;
}

View File

@@ -22,36 +22,40 @@
*/
#include "winbindd.h"
#include "sids.h"
BOOL domain_handles_open(struct winbindd_domain *domain)
/* Debug connection state */
void debug_conn_state(void)
{
return domain->sam_handle_open &&
domain->sam_dom_handle_open &&
rpc_hnd_ok(&domain->sam_handle) &&
rpc_hnd_ok(&domain->sam_dom_handle);
struct winbindd_domain *domain;
DEBUG(3, ("server: dc=%s, pwdb_init=%d, lsa_hnd=%d\n",
server_state.controller,
server_state.pwdb_initialised,
server_state.lsa_handle_open));
for (domain = domain_list; domain; domain = domain->next) {
DEBUG(3, ("%s: dc=%s, got_sid=%d, sam_hnd=%d sam_dom_hnd=%d\n",
domain->name, domain->controller,
domain->got_domain_info, domain->sam_handle_open,
domain->sam_dom_handle_open));
}
}
static BOOL resolve_dc_name(char *domain_name, fstring domain_controller)
{
struct in_addr ip;
extern pstring global_myname;
/* if its our primary domain and password server is not '*' then use the
password server parameter */
if (strcmp(domain_name,lp_workgroup()) == 0 && !lp_wildcard_dc()) {
fstrcpy(domain_controller, lp_passwordserver());
return True;
}
if (!resolve_name(domain_name, &ip, 0x1B)) return False;
return lookup_pdc_name(global_myname, domain_name, &ip,
domain_controller);
}
/* Add a trusted domain to our list of domains */
static struct winbindd_domain *add_trusted_domain(char *domain_name)
{
struct winbindd_domain *domain;
struct winbindd_domain *domain, *tmp;
for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
if (strcmp(domain_name, tmp->name) == 0) {
DEBUG(3, ("domain %s already in trusted list\n",
domain_name));
return tmp;
}
}
DEBUG(1, ("adding trusted domain %s\n", domain_name));
@@ -77,12 +81,13 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name)
}
/* Look up global info for the winbind daemon */
static BOOL get_trusted_domains(void)
{
uint32 enum_ctx = 0;
uint32 num_doms = 0;
char **domains = NULL;
DOM_SID **sids = NULL;
DOM_SID *sids = NULL;
BOOL result;
int i;
@@ -110,41 +115,33 @@ static BOOL get_trusted_domains(void)
}
}
/* Free memory */
free_char_array(num_doms, domains);
free_sid_array(num_doms, sids);
return True;
}
/* Open sam and sam domain handles */
/* Open sam and sam domain handles to a domain and cache the results */
static BOOL open_sam_handles(struct winbindd_domain *domain)
{
/* Get domain info */
/* Get domain info (sid and controller name) */
if (!domain->got_domain_info) {
domain->got_domain_info = get_domain_info(domain);
if (!domain->got_domain_info) return False;
}
if ((domain->sam_handle_open && !rpc_hnd_ok(&domain->sam_handle)) ||
(domain->sam_dom_handle_open &&
!rpc_hnd_ok(&domain->sam_dom_handle))) {
/* Shut down existing sam handles */
domain->got_domain_info = get_domain_info(domain);
if (domain->sam_dom_handle_open) {
samr_close(&domain->sam_dom_handle);
domain->sam_dom_handle_open = False;
}
if (domain->sam_handle_open) {
samr_close(&domain->sam_handle);
domain->sam_handle_open = False;
}
}
/* Open sam handle if it isn't already open */
if (!domain->sam_handle_open) {
/* Open sam handle */
domain->sam_handle_open =
samr_connect(domain->controller,
@@ -152,46 +149,116 @@ static BOOL open_sam_handles(struct winbindd_domain *domain)
&domain->sam_handle);
if (!domain->sam_handle_open) return False;
}
/* Open sam domain handle if it isn't already open */
if (!domain->sam_dom_handle_open) {
/* Open sam domain handle */
domain->sam_dom_handle_open =
samr_open_domain(&domain->sam_handle,
SEC_RIGHTS_MAXIMUM_ALLOWED,
&domain->sid, &domain->sam_dom_handle);
&domain->sid,
&domain->sam_dom_handle);
if (!domain->sam_dom_handle_open) return False;
}
return True;
}
/* Close all LSA and SAM connections */
static void winbindd_kill_connections(void)
static BOOL rpc_hnd_ok(CLI_POLICY_HND *hnd)
{
struct winbindd_cli_state *cli;
struct winbindd_domain *domain;
return hnd->cli->fd != -1;
}
DEBUG(1,("killing winbindd connections\n"));
/* Return true if the SAM domain handles are open and responding. */
/* Close LSA connection */
BOOL domain_handles_open(struct winbindd_domain *domain)
{
time_t t;
BOOL result;
/* Check we haven't checked too recently */
t = time(NULL);
if ((t - domain->last_check) < WINBINDD_ESTABLISH_LOOP) {
return domain->sam_handle_open &&
domain->sam_dom_handle_open;
}
DEBUG(3, ("checking domain handles for domain %s\n", domain->name));
debug_conn_state();
domain->last_check = t;
/* Open sam handles if they are marked as closed */
if (!domain->sam_handle_open || !domain->sam_dom_handle_open) {
reopen:
DEBUG(3, ("opening sam handles\n"));
return open_sam_handles(domain);
}
/* Check sam handles are ok - the domain controller may have failed
and we need to move to a BDC. */
if (!rpc_hnd_ok(&domain->sam_handle) ||
!rpc_hnd_ok(&domain->sam_dom_handle)) {
/* We want to close the current connection but attempt
to open a new set, possibly to a new dc. If this
doesn't work then return False as we have no dc
to talk to. */
DEBUG(3, ("sam handles not responding\n"));
winbindd_kill_connections(domain);
goto reopen;
}
result = domain->sam_handle_open && domain->sam_dom_handle_open;
return result;
}
/* Shut down connections to all domain controllers */
void winbindd_kill_connections(struct winbindd_domain *domain)
{
BOOL is_server = False;
struct winbindd_domain *server_domain;
/* Find pointer to domain of pdc */
server_domain = find_domain_from_name(lp_workgroup());
if (!server_domain) return;
/* If NULL passed, use pdc */
if (!domain) {
domain = server_domain;
}
if (domain == server_domain ||
strequal(domain->name, lp_workgroup())) {
is_server = True;
}
/* Log a level 0 message - this is probably a domain controller
failure */
DEBUG(0, ("killing connections to domain %s with controller %s\n",
domain->name, domain->controller));
debug_conn_state();
if (is_server) {
server_state.pwdb_initialised = False;
server_state.lsa_handle_open = False;
lsa_close(&server_state.lsa_handle);
}
/* Close SAM connections */
domain = domain_list;
while(domain) {
struct winbindd_domain *next;
/* Close SAM handles */
/* Close domain sam handles but don't free them as this
severely traumatises the getent state. The connections
will be reopened later. */
if (domain->sam_dom_handle_open) {
samr_close(&domain->sam_dom_handle);
@@ -203,7 +270,29 @@ static void winbindd_kill_connections(void)
domain->sam_handle_open = False;
}
/* Remove from list */
/* Re-lookup domain info which includes domain controller name */
domain->got_domain_info = False;
}
/* Kill connections to all servers */
void winbindd_kill_all_connections(void)
{
struct winbindd_domain *domain;
/* Iterate over domain list */
domain = domain_list;
while (domain) {
struct winbindd_domain *next;
/* Kill conections */
winbindd_kill_connections(domain);
/* Remove domain from list */
next = domain->next;
DLIST_REMOVE(domain_list, domain);
@@ -211,68 +300,106 @@ static void winbindd_kill_connections(void)
domain = next;
}
/* We also need to go through and trash any pointers to domains in
get{pw,gr}ent state records */
for (cli = client_list; cli; cli = cli->next) {
free_getent_state(cli->getpwent_state);
free_getent_state(cli->getgrent_state);
}
}
/* Try to establish connections to NT servers */
void establish_connections(void)
static BOOL get_any_dc_name(char *domain, fstring srv_name)
{
struct in_addr *ip_list, dc_ip;
extern pstring global_myname;
int count, i;
/* Lookup domain controller name */
if (!get_dc_list(False, lp_workgroup(), &ip_list, &count))
return False;
/* Firstly choose a PDC/BDC who has the same network address as any
of our interfaces. */
for (i = 0; i < count; i++) {
if(!is_local_net(ip_list[i]))
goto got_ip;
}
i = (sys_random() % count);
got_ip:
dc_ip = ip_list[i];
free(ip_list);
if (!lookup_pdc_name(global_myname, lp_workgroup(),
&dc_ip, server_state.controller))
return False;
return True;
}
/* Attempt to connect to all domain controllers we know about */
void establish_connections(BOOL force_reestablish)
{
struct winbindd_domain *domain;
static time_t lastt;
time_t t;
/* Check we haven't checked too recently */
t = time(NULL);
if (t - lastt < WINBINDD_ESTABLISH_LOOP) return;
if ((t - lastt < WINBINDD_ESTABLISH_LOOP) && !force_reestablish) {
return;
}
lastt = t;
/* maybe the connection died - if so then close up and restart */
DEBUG(3, ("establishing connections\n"));
debug_conn_state();
/* Maybe the connection died - if so then close up and restart */
if (server_state.pwdb_initialised &&
server_state.lsa_handle_open &&
!rpc_hnd_ok(&server_state.lsa_handle)) {
winbindd_kill_connections();
winbindd_kill_connections(NULL);
}
if (!server_state.pwdb_initialised) {
fstrcpy(server_state.controller, lp_passwordserver());
if (lp_wildcard_dc()) {
if (!resolve_dc_name(lp_workgroup(), server_state.controller)) {
/* Lookup domain controller name */
if (!get_any_dc_name(lp_workgroup(),
server_state.controller)) {
return;
}
}
server_state.pwdb_initialised = pwdb_initialise(False);
if (!server_state.pwdb_initialised) return;
/* Initialise password database and sids */
// server_state.pwdb_initialised = pwdb_initialise(False);
server_state.pwdb_initialised = True;
if (!server_state.pwdb_initialised)
return;
}
/* Open lsa handle if it isn't already open */
if (!server_state.lsa_handle_open) {
server_state.lsa_handle_open =
lsa_open_policy(server_state.controller, &server_state.lsa_handle,
False, SEC_RIGHTS_MAXIMUM_ALLOWED);
lsa_open_policy(server_state.controller,
False, SEC_RIGHTS_MAXIMUM_ALLOWED,
&server_state.lsa_handle);
if (!server_state.lsa_handle_open) return;
/* now we can talk to the server we can get some info */
/* Now we can talk to the server we can get some info */
get_trusted_domains();
}
for (domain=domain_list; domain; domain=domain->next) {
if (!domain_handles_open(domain)) {
open_sam_handles(domain);
debug_conn_state();
}
}
}
/* Connect to a domain controller using get_any_dc_name() to discover
the domain name and sid */
BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
{
fstring level5_dom;
@@ -280,7 +407,7 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
uint32 enum_ctx = 0;
uint32 num_doms = 0;
char **domains = NULL;
DOM_SID **sids = NULL;
DOM_SID *sids = NULL;
if (domain == NULL) {
return False;
@@ -289,7 +416,10 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
DEBUG(1, ("looking up sid for domain %s\n", domain_name));
/* Get controller name for domain */
if (!resolve_dc_name(domain_name, domain->controller)) {
if (!get_any_dc_name(domain_name, domain->controller)) {
DEBUG(0, ("Could not resolve domain controller for domain %s\n",
domain_name));
return False;
}
@@ -312,7 +442,7 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
for(i = 0; i < num_doms; i++) {
if (strequal(domain_name, domains[i])) {
sid_copy(&domain->sid, sids[i]);
sid_copy(&domain->sid, &sids[i]);
found = True;
break;
}
@@ -321,15 +451,9 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain)
res = found;
}
/* Free memory */
free_char_array(num_doms, domains);
free_sid_array(num_doms, sids);
return res;
}
/* Lookup domain controller and sid for a domain */
BOOL get_domain_info(struct winbindd_domain *domain)
@@ -339,8 +463,14 @@ BOOL get_domain_info(struct winbindd_domain *domain)
DEBUG(1, ("Getting domain info for domain %s\n", domain->name));
/* Lookup domain sid */
if (!lookup_domain_sid(domain->name, domain)) {
DEBUG(0, ("could not find sid for domain %s\n", domain->name));
/* Could be a DC failure - shut down connections to this domain */
winbindd_kill_connections(domain);
return False;
}
@@ -356,8 +486,7 @@ BOOL get_domain_info(struct winbindd_domain *domain)
/* Lookup a sid in a domain from a name */
BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
char *name, DOM_SID *sid,
BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid,
enum SID_NAME_USE *type)
{
int num_sids = 0, num_names = 1;
@@ -403,8 +532,7 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
/* Lookup a name in a domain from a sid */
BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
DOM_SID *sid, char *name,
BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name,
enum SID_NAME_USE *type)
{
int num_sids = 1, num_names = 0;
@@ -413,8 +541,9 @@ BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
BOOL res;
/* Lookup name */
res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, &sid, &names,
&types, &num_names);
res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, sid,
&names, &types, &num_names);
/* Return name and type if successful */
@@ -446,9 +575,40 @@ BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
uint32 user_rid, SAM_USERINFO_CTR *user_info)
{
if (!domain_handles_open(domain)) return False;
return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15,
user_rid, user_info);
}
return get_samr_query_userinfo(&domain->sam_dom_handle, 0x15, user_rid, user_info);
/* Lookup groups a user is a member of. I wish Unix had a call like this! */
BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain,
uint32 user_rid, uint32 *num_groups,
DOM_GID **user_groups)
{
POLICY_HND user_pol;
BOOL result;
if (!samr_open_user(&domain->sam_dom_handle,
SEC_RIGHTS_MAXIMUM_ALLOWED,
user_rid, &user_pol)) {
return False;
}
if (cli_samr_query_usergroups(domain->sam_dom_handle.cli,
domain->sam_dom_handle.mem_ctx,
&user_pol, num_groups, user_groups)
!= NT_STATUS_NOPROBLEMO) {
result = False;
goto done;
}
result = True;
done:
cli_samr_close(domain->sam_dom_handle.cli,
domain->sam_dom_handle.mem_ctx, &user_pol);
return True;
}
/* Lookup group information from a rid */
@@ -456,9 +616,8 @@ BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain,
BOOL winbindd_lookup_groupinfo(struct winbindd_domain *domain,
uint32 group_rid, GROUP_INFO_CTR *info)
{
if (!domain_handles_open(domain)) return False;
return get_samr_query_groupinfo(&domain->sam_dom_handle, 1, group_rid, info);
return get_samr_query_groupinfo(&domain->sam_dom_handle, 1,
group_rid, info);
}
/* Lookup group membership given a rid */
@@ -468,40 +627,48 @@ BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
uint32 **rid_mem, char ***names,
enum SID_NAME_USE **name_types)
{
if (!domain_handles_open(domain)) return False;
return sam_query_groupmem(&domain->sam_dom_handle, group_rid, num_names,
rid_mem, names, name_types);
}
/* Lookup alias membership given a rid */
int winbindd_lookup_aliasmem(struct winbindd_domain *domain,
uint32 alias_rid, uint32 *num_names,
DOM_SID ***sids, char ***names,
enum SID_NAME_USE **name_types)
{
/* Open sam handles */
if (!domain_handles_open(domain)) return False;
return sam_query_aliasmem(domain->controller,
&domain->sam_dom_handle, alias_rid, num_names,
sids, names, name_types);
return sam_query_groupmem(&domain->sam_dom_handle, group_rid,
num_names, rid_mem, names, name_types);
}
/* Globals for domain list stuff */
struct winbindd_domain *domain_list = NULL;
/* Given a domain name, return the struct winbindd domain info for it */
/* Given a domain name, return the struct winbindd domain info for it
if it is actually working. */
struct winbindd_domain *find_domain_from_name(char *domain_name)
{
struct winbindd_domain *tmp;
/* Search through list */
for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
if (strcmp(domain_name, tmp->name) == 0) {
if (!tmp->got_domain_info) {
get_domain_info(tmp);
}
return tmp->got_domain_info ? tmp : NULL;
}
}
/* Not found */
return NULL;
}
/* Given a domain name, return the struct winbindd domain info for it */
struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
{
struct winbindd_domain *tmp;
/* Search through list */
for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
if (sid_equal(sid, &tmp->sid)) {
if (!tmp->got_domain_info) return NULL;
return tmp;
}
@@ -544,14 +711,14 @@ static BOOL parse_id_list(char *paramstr, BOOL is_user)
/* Give a nicer error message if no parameters specified */
if (strequal(paramstr, "")) {
DEBUG(0, ("winbid %s parameter missing\n", is_user ? "uid" : "gid"));
DEBUG(0, ("winbind %s parameter missing\n", is_user ? "uid" : "gid"));
return False;
}
/* Parse entry */
if (sscanf(paramstr, "%u-%u", &id_low, &id_high) != 2) {
DEBUG(0, ("winbid %s parameter invalid\n",
DEBUG(0, ("winbind %s parameter invalid\n",
is_user ? "uid" : "gid"));
return False;
}
@@ -588,7 +755,7 @@ BOOL winbindd_param_init(void)
}
if (server_state.gid_low > server_state.gid_high) {
DEBUG(0, ("gid range for invalid\n"));
DEBUG(0, ("gid range invalid\n"));
return False;
}
@@ -597,66 +764,142 @@ BOOL winbindd_param_init(void)
/* Convert a enum winbindd_cmd to a string */
struct cmdstr_table {
enum winbindd_cmd cmd;
char *desc;
};
static struct cmdstr_table cmdstr_table[] = {
/* User functions */
{ WINBINDD_GETPWNAM_FROM_USER, "getpwnam from user" },
{ WINBINDD_GETPWNAM_FROM_UID, "getpwnam from uid" },
{ WINBINDD_SETPWENT, "setpwent" },
{ WINBINDD_ENDPWENT, "endpwent" },
{ WINBINDD_GETPWENT, "getpwent" },
{ WINBINDD_GETGROUPS, "getgroups" },
/* Group functions */
{ WINBINDD_GETGRNAM_FROM_GROUP, "getgrnam from group" },
{ WINBINDD_GETGRNAM_FROM_GID, "getgrnam from gid" },
{ WINBINDD_SETGRENT, "setgrent" },
{ WINBINDD_ENDGRENT, "endgrent" },
{ WINBINDD_GETGRENT, "getgrent" },
/* PAM auth functions */
{ WINBINDD_PAM_AUTH, "pam auth" },
{ WINBINDD_PAM_CHAUTHTOK, "pam chauthtok" },
/* List things */
{ WINBINDD_LIST_USERS, "list users" },
{ WINBINDD_LIST_GROUPS, "list groups" },
{ WINBINDD_LIST_TRUSTDOM, "list trusted domains" },
/* SID related functions */
{ WINBINDD_LOOKUPSID, "lookup sid" },
{ WINBINDD_LOOKUPNAME, "lookup name" },
/* S*RS related functions */
{ WINBINDD_SID_TO_UID, "sid to uid" },
{ WINBINDD_SID_TO_GID, "sid to gid " },
{ WINBINDD_GID_TO_SID, "gid to sid" },
{ WINBINDD_UID_TO_SID, "uid to sid" },
/* Miscellaneous other stuff */
{ WINBINDD_CHECK_MACHACC, "check machine acct pw" },
/* End of list */
{ WINBINDD_NUM_CMDS, NULL }
};
char *winbindd_cmd_to_string(enum winbindd_cmd cmd)
{
char *result;
struct cmdstr_table *table = cmdstr_table;
char *result = NULL;
switch (cmd) {
case WINBINDD_GETPWNAM_FROM_USER:
result = "getpwnam from user";
for(table = cmdstr_table; table->desc; table++) {
if (cmd == table->cmd) {
result = table->desc;
break;
}
}
case WINBINDD_GETPWNAM_FROM_UID:
result = "getpwnam from uid";
break;
case WINBINDD_GETGRNAM_FROM_GROUP:
result = "getgrnam from group";
break;
case WINBINDD_GETGRNAM_FROM_GID:
result = "getgrnam from gid";
break;
case WINBINDD_SETPWENT:
result = "setpwent";
break;
case WINBINDD_ENDPWENT:
result = "endpwent";
break;
case WINBINDD_GETPWENT:
result = "getpwent";
break;
case WINBINDD_SETGRENT:
result = "setgrent";
break;
case WINBINDD_ENDGRENT:
result = "endgrent";
break;
case WINBINDD_GETGRENT:
result = "getgrent";
break;
case WINBINDD_PAM_AUTH:
result = "pam_auth";
break;
default:
if (result == NULL) {
result = "invalid command";
break;
}
return result;
};
/* find the sequence number for a domain */
uint32 domain_sequence_number(char *domain_name)
{
struct winbindd_domain *domain;
SAM_UNK_CTR ctr;
domain = find_domain_from_name(domain_name);
if (!domain) return DOM_SEQUENCE_NONE;
if (!samr_query_dom_info(&domain->sam_dom_handle, 2, &ctr)) {
/* If this fails, something bad has gone wrong */
winbindd_kill_connections(domain);
DEBUG(2,("domain sequence query failed\n"));
return DOM_SEQUENCE_NONE;
}
DEBUG(4,("got domain sequence number for %s of %u\n",
domain_name, (unsigned)ctr.info.inf2.seq_num));
return ctr.info.inf2.seq_num;
}
/* Query display info for a domain. This returns enough information plus a
bit extra to give an overview of domain users for the User Manager
application. */
uint32 winbindd_query_dispinfo(struct winbindd_domain *domain,
uint32 *start_ndx, uint16 info_level,
uint32 *num_entries, SAM_DISPINFO_CTR *ctr)
{
uint32 status;
status = samr_query_dispinfo(&domain->sam_dom_handle, start_ndx,
info_level, num_entries, ctr);
return status;
}
/* Check if a domain is present in a comma-separated list of domains */
BOOL check_domain_env(char *domain_env, char *domain)
{
fstring name;
char *tmp = domain_env;
while(next_token(&tmp, name, ",", sizeof(fstring))) {
if (strequal(name, domain)) {
return True;
}
}
return False;
}
/* Parse a string of the form DOMAIN/user into a domain and a user */
/* parse a string of the form DOMAIN/user into a domain and a user */
void parse_domain_user(char *domuser, fstring domain, fstring user)
{
char *p;
@@ -673,24 +916,5 @@ void parse_domain_user(char *domuser, fstring domain, fstring user)
fstrcpy(user, p+1);
fstrcpy(domain, domuser);
domain[PTR_DIFF(p, domuser)] = 0;
}
/* find the sequence number for a domain */
uint32 domain_sequence_number(char *domain_name)
{
struct winbindd_domain *domain;
SAM_UNK_CTR ctr;
domain = find_domain_from_name(domain_name);
if (!domain) return DOM_SEQUENCE_NONE;
if (!samr_query_dom_info(&domain->sam_dom_handle, 2, &ctr)) {
DEBUG(2,("domain sequence query failed\n"));
return DOM_SEQUENCE_NONE;
}
DEBUG(4,("got domain sequence number for %s of %u\n",
domain_name, (unsigned)ctr.info.inf2.seq_num));
return ctr.info.inf2.seq_num;
strupper(domain);
}