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:
@@ -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 $@"
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user