mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
brought the winbindd code into head
this does not yet compile, but I'm working on that.
This commit is contained in:
parent
6c5d139844
commit
3fb862531a
282
source/nsswitch/common.c
Normal file
282
source/nsswitch/common.c
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
winbind client common code
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "ntdom_config.h"
|
||||
#include "winbindd_ntdom.h"
|
||||
|
||||
/* Global variables. These are effectively the client state information */
|
||||
|
||||
static int established_socket = -1; /* fd for winbindd socket */
|
||||
|
||||
/*
|
||||
* Utility and helper functions
|
||||
*/
|
||||
|
||||
void init_request(struct winbindd_request *req,int rq_type)
|
||||
{
|
||||
static char *domain_env;
|
||||
static BOOL initialised;
|
||||
|
||||
req->cmd = rq_type;
|
||||
req->pid = getpid();
|
||||
req->domain[0] = '\0';
|
||||
|
||||
if (!initialised) {
|
||||
initialised = True;
|
||||
domain_env = getenv(WINBINDD_DOMAIN_ENV);
|
||||
}
|
||||
|
||||
if (domain_env) {
|
||||
strncpy(req->domain, domain_env,
|
||||
sizeof(req->domain) - 1);
|
||||
req->domain[sizeof(req->domain) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Close established socket */
|
||||
|
||||
void close_sock(void)
|
||||
{
|
||||
if (established_socket != -1) {
|
||||
close(established_socket);
|
||||
established_socket = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect to winbindd socket */
|
||||
|
||||
static int open_pipe_sock(void)
|
||||
{
|
||||
struct sockaddr_un sunaddr;
|
||||
static pid_t our_pid;
|
||||
struct stat st;
|
||||
pstring path;
|
||||
|
||||
if (our_pid != getpid()) {
|
||||
if (established_socket != -1) {
|
||||
close(established_socket);
|
||||
}
|
||||
established_socket = -1;
|
||||
our_pid = getpid();
|
||||
}
|
||||
|
||||
if (established_socket != -1) {
|
||||
return established_socket;
|
||||
}
|
||||
|
||||
/* Check permissions on unix socket directory */
|
||||
|
||||
if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode) || (st.st_uid != 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect to socket */
|
||||
|
||||
strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
|
||||
strncat(path, "/", sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
|
||||
strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
|
||||
ZERO_STRUCT(sunaddr);
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
|
||||
|
||||
/* If socket file doesn't exist, don't bother trying to connect with
|
||||
retry. This is an attempt to make the system usable when the
|
||||
winbindd daemon is not running. */
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check permissions on unix socket file */
|
||||
|
||||
if (!S_ISSOCK(st.st_mode) || (st.st_uid != 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect to socket */
|
||||
|
||||
if ((established_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(established_socket, (struct sockaddr *)&sunaddr,
|
||||
sizeof(sunaddr)) == -1) {
|
||||
close_sock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return established_socket;
|
||||
}
|
||||
|
||||
/* Write data to winbindd socket with timeout */
|
||||
|
||||
int write_sock(void *buffer, int count)
|
||||
{
|
||||
int result, nwritten;
|
||||
|
||||
/* Open connection to winbind daemon */
|
||||
|
||||
restart:
|
||||
|
||||
if (open_pipe_sock() == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write data to socket */
|
||||
|
||||
nwritten = 0;
|
||||
|
||||
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(). */
|
||||
|
||||
FD_ZERO(&r_fds);
|
||||
FD_SET(established_socket, &r_fds);
|
||||
ZERO_STRUCT(tv);
|
||||
|
||||
if ((selret = select(established_socket + 1, &r_fds, NULL, NULL,
|
||||
&tv)) == -1) {
|
||||
close_sock();
|
||||
return -1; /* Select error */
|
||||
}
|
||||
|
||||
/* Write should be OK if fd not available for reading */
|
||||
|
||||
if (!FD_ISSET(established_socket, &r_fds)) {
|
||||
|
||||
/* Do the write */
|
||||
|
||||
result = write(established_socket, (char *)buffer + nwritten,
|
||||
count - nwritten);
|
||||
|
||||
if ((result == -1) || (result == 0)) {
|
||||
|
||||
/* Write failed */
|
||||
|
||||
close_sock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
nwritten += result;
|
||||
|
||||
} else {
|
||||
|
||||
/* Pipe has closed on remote end */
|
||||
|
||||
close_sock();
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
/* Read data from winbindd socket with timeout */
|
||||
|
||||
static int read_sock(void *buffer, int count)
|
||||
{
|
||||
int result, nread;
|
||||
|
||||
/* Read data from socket */
|
||||
|
||||
nread = 0;
|
||||
|
||||
while(nread < count) {
|
||||
|
||||
result = read(established_socket, (char *)buffer + nread,
|
||||
count - nread);
|
||||
|
||||
if ((result == -1) || (result == 0)) {
|
||||
|
||||
/* Read failed. I think the only useful thing we can do here
|
||||
is just return -1 and fail since the transaction has failed
|
||||
half way through. */
|
||||
|
||||
close_sock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
nread += result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read reply */
|
||||
|
||||
int read_reply(struct winbindd_response *response)
|
||||
{
|
||||
int result1, result2;
|
||||
|
||||
if (!response) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read fixed length response */
|
||||
|
||||
if ((result1 = read_sock(response, sizeof(struct winbindd_response)))
|
||||
== -1) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read variable length response */
|
||||
|
||||
if (response->length > sizeof(struct winbindd_response)) {
|
||||
int extra_data_len = response->length -
|
||||
sizeof(struct winbindd_response);
|
||||
|
||||
/* Mallocate memory for extra data */
|
||||
|
||||
if (!(response->extra_data = malloc(extra_data_len))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((result2 = read_sock(response->extra_data, extra_data_len))
|
||||
== -1) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return total amount of data read */
|
||||
|
||||
return result1 + result2;
|
||||
}
|
||||
|
388
source/nsswitch/pam_winbind.c
Normal file
388
source/nsswitch/pam_winbind.c
Normal file
@ -0,0 +1,388 @@
|
||||
/* pam_winbind module
|
||||
|
||||
Copyright Andrew Tridgell <tridge@samba.org> 2000
|
||||
|
||||
largely based on pam_userdb by Christian Gafton <gafton@redhat.com>
|
||||
*/
|
||||
|
||||
#include <features.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define MODULE_NAME "pam_winbind"
|
||||
#define PAM_SM_AUTH
|
||||
#define PAM_SM_ACCOUNT
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/_pam_macros.h>
|
||||
|
||||
#define PAM_DEBUG_ARG (1<<0)
|
||||
#define PAM_USE_AUTHTOK_ARG (1<<1)
|
||||
#define PAM_UNKNOWN_OK_ARG (1<<2)
|
||||
|
||||
#include "ntdom_config.h"
|
||||
#include "winbindd_ntdom.h"
|
||||
|
||||
/* prototypes from common.c */
|
||||
void init_request(struct winbindd_request *req,int rq_type);
|
||||
int write_sock(void *buffer, int count);
|
||||
int read_reply(struct winbindd_response *response);
|
||||
|
||||
/* some syslogging */
|
||||
static void _pam_log(int err, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
|
||||
vsyslog(err, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
static int ctrl = 0;
|
||||
|
||||
static int _pam_parse(int argc, const char **argv)
|
||||
{
|
||||
/* step through arguments */
|
||||
for (ctrl = 0; argc-- > 0; ++argv) {
|
||||
|
||||
/* generic options */
|
||||
|
||||
if (!strcmp(*argv,"debug"))
|
||||
ctrl |= PAM_DEBUG_ARG;
|
||||
else if (!strcasecmp(*argv, "use_authtok"))
|
||||
ctrl |= PAM_USE_AUTHTOK_ARG;
|
||||
else if (!strcasecmp(*argv, "unknown_ok"))
|
||||
ctrl |= PAM_UNKNOWN_OK_ARG;
|
||||
else {
|
||||
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
/* talk to winbindd */
|
||||
static int winbind_request(int req_type, const char *user, const char *pass)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
|
||||
strncpy(request.data.auth.user, user, sizeof(request.data.auth.user)-1);
|
||||
strncpy(request.data.auth.pass, pass, sizeof(request.data.auth.pass)-1);
|
||||
|
||||
/* Fill in request and send down pipe */
|
||||
init_request(&request, req_type);
|
||||
|
||||
if (write_sock(&request, sizeof(request)) == -1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Wait for reply */
|
||||
if (read_reply(&response) == -1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Copy reply data from socket */
|
||||
if (response.result != WINBINDD_OK) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up an user name and checks the password
|
||||
*
|
||||
* return values:
|
||||
* 1 = User not found
|
||||
* 0 = OK
|
||||
* -1 = Password incorrect
|
||||
* -2 = System error
|
||||
*/
|
||||
static int user_lookup(const char *user, const char *pass)
|
||||
{
|
||||
return winbind_request(WINBINDD_PAM_AUTH, user, pass);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a user has an account
|
||||
*
|
||||
* return values:
|
||||
* 1 = User not found
|
||||
* 0 = OK
|
||||
* -1 = System error
|
||||
*/
|
||||
static int valid_user(const char *user)
|
||||
{
|
||||
if (getpwnam(user)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --- authentication management functions --- */
|
||||
|
||||
/*
|
||||
* dummy conversation function sending exactly one prompt
|
||||
* and expecting exactly one response from the other party
|
||||
*/
|
||||
static int converse(pam_handle_t *pamh,
|
||||
struct pam_message **message,
|
||||
struct pam_response **response)
|
||||
{
|
||||
int retval;
|
||||
struct pam_conv *conv;
|
||||
|
||||
retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
|
||||
if (retval == PAM_SUCCESS)
|
||||
retval = conv->conv(1, (const struct pam_message **)message,
|
||||
response, conv->appdata_ptr);
|
||||
|
||||
return retval; /* propagate error status */
|
||||
}
|
||||
|
||||
|
||||
static char *_pam_delete(register char *xx)
|
||||
{
|
||||
_pam_overwrite(xx);
|
||||
_pam_drop(xx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a conversation function to obtain the user's password
|
||||
*/
|
||||
static int conversation(pam_handle_t *pamh)
|
||||
{
|
||||
struct pam_message msg[2],*pmsg[2];
|
||||
struct pam_response *resp;
|
||||
int retval;
|
||||
char * token;
|
||||
|
||||
pmsg[0] = &msg[0];
|
||||
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
msg[0].msg = "Password: ";
|
||||
|
||||
/* so call the conversation expecting i responses */
|
||||
resp = NULL;
|
||||
retval = converse(pamh, pmsg, &resp);
|
||||
|
||||
if (resp != NULL) {
|
||||
char * const item;
|
||||
/* interpret the response */
|
||||
if (retval == PAM_SUCCESS) { /* a good conversation */
|
||||
token = x_strdup(resp[0].resp);
|
||||
if (token == NULL) {
|
||||
return PAM_AUTHTOK_RECOVER_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the auth token */
|
||||
retval = pam_set_item(pamh, PAM_AUTHTOK, token);
|
||||
token = _pam_delete(token); /* clean it up */
|
||||
if ( (retval != PAM_SUCCESS) ||
|
||||
(retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
_pam_drop_reply(resp, 1);
|
||||
} else {
|
||||
retval = (retval == PAM_SUCCESS)
|
||||
? PAM_AUTHTOK_RECOVER_ERR:retval ;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
const char *username;
|
||||
const char *password;
|
||||
int retval = PAM_AUTH_ERR;
|
||||
|
||||
/* parse arguments */
|
||||
ctrl = _pam_parse(argc, argv);
|
||||
|
||||
/* Get the username */
|
||||
retval = pam_get_user(pamh, &username, NULL);
|
||||
if ((retval != PAM_SUCCESS) || (!username)) {
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_DEBUG,"can not get the username");
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
|
||||
if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
|
||||
/* Converse just to be sure we have the password */
|
||||
retval = conversation(pamh);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
_pam_log(LOG_ERR, "could not obtain password for `%s'",
|
||||
username);
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the password */
|
||||
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
_pam_log(LOG_ERR, "Could not retrive user's password");
|
||||
return PAM_AUTHTOK_ERR;
|
||||
}
|
||||
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
|
||||
username, password);
|
||||
|
||||
/* Now use the username to look up password */
|
||||
retval = user_lookup(username, password);
|
||||
switch (retval) {
|
||||
case -2:
|
||||
/* some sort of system error. The log was already printed */
|
||||
return PAM_SERVICE_ERR;
|
||||
case -1:
|
||||
/* incorrect password */
|
||||
_pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
|
||||
return PAM_AUTH_ERR;
|
||||
case 1:
|
||||
/* the user does not exist */
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_NOTICE, "user `%s' not found",
|
||||
username);
|
||||
if (ctrl & PAM_UNKNOWN_OK_ARG) {
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
return PAM_USER_UNKNOWN;
|
||||
case 0:
|
||||
/* Otherwise, the authentication looked good */
|
||||
_pam_log(LOG_NOTICE, "user '%s' granted acces", username);
|
||||
return PAM_SUCCESS;
|
||||
default:
|
||||
/* we don't know anything about this return value */
|
||||
_pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
|
||||
retval, username);
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
/* should not be reached */
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_setcred(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Account management. We want to verify that the account exists
|
||||
* before returning PAM_SUCCESS
|
||||
*/
|
||||
PAM_EXTERN
|
||||
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
const char *username;
|
||||
int retval = PAM_USER_UNKNOWN;
|
||||
|
||||
/* parse arguments */
|
||||
ctrl = _pam_parse(argc, argv);
|
||||
|
||||
/* Get the username */
|
||||
retval = pam_get_user(pamh, &username, NULL);
|
||||
if ((retval != PAM_SUCCESS) || (!username)) {
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_DEBUG,"can not get the username");
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
|
||||
/* Verify the username */
|
||||
retval = valid_user(username);
|
||||
switch (retval) {
|
||||
case -1:
|
||||
/* some sort of system error. The log was already printed */
|
||||
return PAM_SERVICE_ERR;
|
||||
case 1:
|
||||
/* the user does not exist */
|
||||
if (ctrl & PAM_DEBUG_ARG)
|
||||
_pam_log(LOG_NOTICE, "user `%s' not found",
|
||||
username);
|
||||
if (ctrl & PAM_UNKNOWN_OK_ARG)
|
||||
return PAM_IGNORE;
|
||||
return PAM_USER_UNKNOWN;
|
||||
case 0:
|
||||
/* Otherwise, the authentication looked good */
|
||||
_pam_log(LOG_NOTICE, "user '%s' granted acces", username);
|
||||
return PAM_SUCCESS;
|
||||
default:
|
||||
/* we don't know anything about this return value */
|
||||
_pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
|
||||
retval, username);
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
|
||||
/* should not be reached */
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PAM_STATIC
|
||||
|
||||
/* static module data */
|
||||
|
||||
struct pam_module _pam_userdb_modstruct = {
|
||||
MODULE_NAME,
|
||||
pam_sm_authenticate,
|
||||
pam_sm_setcred,
|
||||
pam_sm_acct_mgmt,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, and the entire permission notice in its entirety,
|
||||
* including the disclaimer of warranties.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this product may be distributed under the terms of
|
||||
* the GNU Public License, in which case the provisions of the GPL are
|
||||
* required INSTEAD OF the above restrictions. (This clause is
|
||||
* necessary due to a potential bad interaction between the GPL and
|
||||
* the restrictions contained in a BSD-style copyright.)
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
465
source/nsswitch/winbind_nss.c
Normal file
465
source/nsswitch/winbind_nss.c
Normal file
@ -0,0 +1,465 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Windows NT Domain nsswitch module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "ntdom_config.h"
|
||||
#include "winbindd_ntdom.h"
|
||||
|
||||
/* prototypes from common.c */
|
||||
void init_request(struct winbindd_request *req,int rq_type);
|
||||
int write_sock(void *buffer, int count);
|
||||
int read_reply(struct winbindd_response *response);
|
||||
|
||||
|
||||
/* Allocate some space from the nss static buffer. The buffer and buflen
|
||||
are the pointers passed in by the C library to the _nss_ntdom_*
|
||||
functions. */
|
||||
|
||||
static char *get_static(char **buffer, int *buflen, int len)
|
||||
{
|
||||
char *result;
|
||||
|
||||
/* Error check. We return false if things aren't set up right, or
|
||||
there isn't enough buffer space left. */
|
||||
|
||||
if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return an index into the static buffer */
|
||||
|
||||
result = *buffer;
|
||||
*buffer += len;
|
||||
*buflen -= len;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* I've copied the strtok() replacement function next_token() from
|
||||
lib/util_str.c as I really don't want to have to link in any other
|
||||
objects if I can possibly avoid it. */
|
||||
|
||||
#ifdef strchr /* Aargh! This points at multibyte_strchr(). )-: */
|
||||
#undef strchr
|
||||
#endif
|
||||
|
||||
static char *last_ptr = NULL;
|
||||
|
||||
BOOL next_token(char **ptr, char *buff, char *sep, size_t bufsize)
|
||||
{
|
||||
char *s;
|
||||
BOOL quoted;
|
||||
size_t len=1;
|
||||
|
||||
if (!ptr) ptr = &last_ptr;
|
||||
if (!ptr) return(False);
|
||||
|
||||
s = *ptr;
|
||||
|
||||
/* default to simple separators */
|
||||
if (!sep) sep = " \t\n\r";
|
||||
|
||||
/* find the first non sep char */
|
||||
while(*s && strchr(sep,*s)) s++;
|
||||
|
||||
/* nothing left? */
|
||||
if (! *s) return(False);
|
||||
|
||||
/* copy over the token */
|
||||
for (quoted = False;
|
||||
len < bufsize && *s && (quoted || !strchr(sep,*s));
|
||||
s++) {
|
||||
|
||||
if (*s == '\"') {
|
||||
quoted = !quoted;
|
||||
} else {
|
||||
len++;
|
||||
*buff++ = *s;
|
||||
}
|
||||
}
|
||||
|
||||
*ptr = (*s) ? s+1 : s;
|
||||
*buff = 0;
|
||||
last_ptr = *ptr;
|
||||
|
||||
return(True);
|
||||
}
|
||||
|
||||
|
||||
/* handle simple types of requests */
|
||||
static enum nss_status generic_request(int req_type,
|
||||
struct winbindd_request *request,
|
||||
struct winbindd_response *response)
|
||||
{
|
||||
struct winbindd_request lrequest;
|
||||
struct winbindd_response lresponse;
|
||||
|
||||
if (!response) response = &lresponse;
|
||||
if (!request) request = &lrequest;
|
||||
|
||||
/* Fill in request and send down pipe */
|
||||
init_request(request, req_type);
|
||||
|
||||
if (write_sock(request, sizeof(*request)) == -1) {
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
/* Wait for reply */
|
||||
if (read_reply(response) == -1) {
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
/* Copy reply data from socket */
|
||||
if (response->result != WINBINDD_OK) {
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Fill a pwent structure from a winbindd_response structure. We use
|
||||
the static data passed to us by libc to put strings and stuff in.
|
||||
Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
|
||||
memory. */
|
||||
|
||||
static enum nss_status fill_pwent(struct passwd *result,
|
||||
struct winbindd_response *response,
|
||||
char **buffer, int *buflen, int *errnop)
|
||||
{
|
||||
struct winbindd_pw *pw = &response->data.pw;
|
||||
|
||||
/* User name */
|
||||
|
||||
if ((result->pw_name =
|
||||
get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->pw_name, pw->pw_name);
|
||||
|
||||
/* Password */
|
||||
|
||||
if ((result->pw_passwd =
|
||||
get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->pw_passwd, pw->pw_passwd);
|
||||
|
||||
/* [ug]id */
|
||||
|
||||
result->pw_uid = pw->pw_uid;
|
||||
result->pw_gid = pw->pw_gid;
|
||||
|
||||
/* GECOS */
|
||||
|
||||
if ((result->pw_gecos =
|
||||
get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->pw_gecos, pw->pw_gecos);
|
||||
|
||||
/* Home directory */
|
||||
|
||||
if ((result->pw_dir =
|
||||
get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->pw_dir, pw->pw_dir);
|
||||
|
||||
/* Logon shell */
|
||||
|
||||
if ((result->pw_shell =
|
||||
get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->pw_shell, pw->pw_shell);
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Fill a grent structure from a winbindd_response structure. We use
|
||||
the static data passed to us by libc to put strings and stuff in.
|
||||
Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
|
||||
memory. */
|
||||
|
||||
static int fill_grent(struct group *result,
|
||||
struct winbindd_response *response,
|
||||
char **buffer, int *buflen, int *errnop)
|
||||
{
|
||||
struct winbindd_gr *gr = &response->data.gr;
|
||||
fstring name;
|
||||
int i;
|
||||
|
||||
/* Group name */
|
||||
|
||||
if ((result->gr_name =
|
||||
get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->gr_name, gr->gr_name);
|
||||
|
||||
/* Password */
|
||||
|
||||
if ((result->gr_passwd =
|
||||
get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy(result->gr_passwd, gr->gr_passwd);
|
||||
|
||||
/* gid */
|
||||
|
||||
result->gr_gid = gr->gr_gid;
|
||||
|
||||
/* Group membership */
|
||||
|
||||
if ((gr->num_gr_mem < 0) || !response->extra_data) {
|
||||
gr->num_gr_mem = 0;
|
||||
}
|
||||
|
||||
if ((result->gr_mem =
|
||||
(char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) *
|
||||
sizeof(char *))) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
if (gr->num_gr_mem == 0) {
|
||||
|
||||
/* Group is empty */
|
||||
|
||||
*(result->gr_mem) = NULL;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Start looking at extra data */
|
||||
|
||||
i = 0;
|
||||
|
||||
while(next_token(&response->extra_data, name, ",", sizeof(fstring))) {
|
||||
|
||||
/* Allocate space for member */
|
||||
|
||||
if (((result->gr_mem)[i] =
|
||||
get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
|
||||
|
||||
/* Out of memory */
|
||||
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
strcpy((result->gr_mem)[i], name);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Terminate list */
|
||||
|
||||
(result->gr_mem)[i] = NULL;
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* NSS user functions
|
||||
*/
|
||||
|
||||
/* Rewind "file pointer" to start of ntdom password database */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_setpwent(void)
|
||||
{
|
||||
return generic_request(WINBINDD_SETPWENT, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Close ntdom password database "file pointer" */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_endpwent(void)
|
||||
{
|
||||
return generic_request(WINBINDD_ENDPWENT, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Fetch the next password entry from ntdom password database */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getpwent_r(struct passwd *result, char *buffer,
|
||||
size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
|
||||
ret = generic_request(WINBINDD_GETPWENT, NULL, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_pwent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
||||
|
||||
/* Return passwd struct from uid */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
|
||||
size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
struct winbindd_request request;
|
||||
|
||||
request.data.uid = uid;
|
||||
|
||||
ret = generic_request(WINBINDD_GETPWNAM_FROM_UID, &request, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_pwent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
||||
|
||||
/* Return passwd struct from username */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getpwnam_r(const char *name, struct passwd *result, char *buffer,
|
||||
size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
struct winbindd_request request;
|
||||
|
||||
strncpy(request.data.username, name, sizeof(request.data.username) - 1);
|
||||
request.data.username[sizeof(request.data.username) - 1] = '\0';
|
||||
|
||||
ret = generic_request(WINBINDD_GETPWNAM_FROM_USER, &request, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_pwent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
||||
|
||||
/*
|
||||
* NSS group functions
|
||||
*/
|
||||
|
||||
/* Rewind "file pointer" to start of ntdom group database */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_setgrent(void)
|
||||
{
|
||||
return generic_request(WINBINDD_SETGRENT, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Close "file pointer" for ntdom group database */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_endgrent(void)
|
||||
{
|
||||
return generic_request(WINBINDD_ENDGRENT, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Get next entry from ntdom group database */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getgrent_r(struct group *result,
|
||||
char *buffer, size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
|
||||
ret = generic_request(WINBINDD_GETGRENT, NULL, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_grent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
||||
|
||||
/* Return group struct from group name */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getgrnam_r(const char *name,
|
||||
struct group *result, char *buffer,
|
||||
size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
struct winbindd_request request;
|
||||
|
||||
strncpy(request.data.groupname, name, sizeof(request.data.groupname));
|
||||
request.data.groupname[sizeof(request.data.groupname) - 1] = '\0';
|
||||
|
||||
ret = generic_request(WINBINDD_GETGRNAM_FROM_GROUP, &request, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_grent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
||||
|
||||
/* Return group struct from gid */
|
||||
|
||||
enum nss_status
|
||||
_nss_ntdom_getgrgid_r(gid_t gid,
|
||||
struct group *result, char *buffer,
|
||||
size_t buflen, int *errnop)
|
||||
{
|
||||
enum nss_status ret;
|
||||
struct winbindd_response response;
|
||||
struct winbindd_request request;
|
||||
|
||||
request.data.gid = gid;
|
||||
|
||||
ret = generic_request(WINBINDD_GETGRNAM_FROM_GID, &request, &response);
|
||||
if (ret != NSS_STATUS_SUCCESS) return ret;
|
||||
|
||||
return fill_grent(result, &response, &buffer, &buflen, errnop);
|
||||
}
|
111
source/nsswitch/winbind_nss_config.h
Normal file
111
source/nsswitch/winbind_nss_config.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _NTDOM_CONFIG_H
|
||||
#define _NTDOM_CONFIG_H
|
||||
|
||||
/* Include header files from data in config.h file */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GRP_H
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <nss.h>
|
||||
|
||||
/* I'm trying really hard not to include anything from smb.h with the
|
||||
result of some silly looking redeclaration of structures. */
|
||||
|
||||
#ifndef _PSTRING
|
||||
#define _PSTRING
|
||||
#define PSTRING_LEN 1024
|
||||
#define FSTRING_LEN 128
|
||||
typedef char pstring[PSTRING_LEN];
|
||||
typedef char fstring[FSTRING_LEN];
|
||||
#endif
|
||||
|
||||
#ifndef _BOOL
|
||||
#define _BOOL /* So we don't typedef BOOL again in vfs.h */
|
||||
#define False (0)
|
||||
#define True (1)
|
||||
#define Auto (2)
|
||||
typedef int BOOL;
|
||||
#endif
|
||||
|
||||
#if !defined(uint32)
|
||||
#if (SIZEOF_INT == 4)
|
||||
#define uint32 unsigned int
|
||||
#elif (SIZEOF_LONG == 4)
|
||||
#define uint32 unsigned long
|
||||
#elif (SIZEOF_SHORT == 4)
|
||||
#define uint32 unsigned short
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(uint16)
|
||||
#if (SIZEOF_SHORT == 4)
|
||||
#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
|
||||
#else /* SIZEOF_SHORT != 4 */
|
||||
#define uint16 unsigned short
|
||||
#endif /* SIZEOF_SHORT != 4 */
|
||||
#endif
|
||||
|
||||
#ifndef uint8
|
||||
#define uint8 unsigned char
|
||||
#endif
|
||||
|
||||
/* zero a structure */
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
/* zero a structure given a pointer to the structure */
|
||||
#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
|
||||
|
||||
#endif
|
663
source/nsswitch/winbindd.c
Normal file
663
source/nsswitch/winbindd.c
Normal file
@ -0,0 +1,663 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
|
||||
/* List of all connected clients */
|
||||
|
||||
static struct winbindd_cli_state *client_list;
|
||||
|
||||
/* Reload configuration */
|
||||
|
||||
static BOOL reload_services_file(void)
|
||||
{
|
||||
pstring servicesf = CONFIGFILE;
|
||||
BOOL ret;
|
||||
|
||||
reopen_logs();
|
||||
ret = lp_load(servicesf,False,False,True);
|
||||
|
||||
reopen_logs();
|
||||
load_interfaces();
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Print client information */
|
||||
|
||||
static void do_print_client_info(void)
|
||||
{
|
||||
struct winbindd_cli_state *client;
|
||||
int i;
|
||||
|
||||
if (client_list == NULL) {
|
||||
DEBUG(0, ("no clients in list\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(0, ("client list is:\n"));
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush client cache */
|
||||
|
||||
static void do_flush_caches(void)
|
||||
{
|
||||
/* Clear cached user and group enumation info */
|
||||
|
||||
winbindd_flush_cache();
|
||||
}
|
||||
|
||||
/* Handle the signal by unlinking socket and exiting */
|
||||
|
||||
static void termination_handler(int signum)
|
||||
{
|
||||
pstring path;
|
||||
|
||||
/* Remove socket file */
|
||||
|
||||
slprintf(path, sizeof(path), "%s/%s",
|
||||
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
|
||||
unlink(path);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static BOOL print_client_info;
|
||||
|
||||
static void sigusr1_handler(int signum)
|
||||
{
|
||||
BlockSignals(True, SIGUSR1);
|
||||
print_client_info = True;
|
||||
BlockSignals(False, SIGUSR1);
|
||||
}
|
||||
|
||||
static BOOL flush_cache;
|
||||
|
||||
static void sighup_handler(int signum)
|
||||
{
|
||||
BlockSignals(True, SIGHUP);
|
||||
flush_cache = True;
|
||||
BlockSignals(False, SIGHUP);
|
||||
}
|
||||
|
||||
/* Create winbindd socket */
|
||||
|
||||
static int create_sock(void)
|
||||
{
|
||||
struct sockaddr_un sunaddr;
|
||||
struct stat st;
|
||||
int sock;
|
||||
mode_t old_umask;
|
||||
pstring path;
|
||||
|
||||
/* Create the socket directory or reuse the existing one */
|
||||
|
||||
if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
|
||||
|
||||
if (errno == ENOENT) {
|
||||
|
||||
/* Create directory */
|
||||
|
||||
if (mkdir(WINBINDD_SOCKET_DIR, 0755) == -1) {
|
||||
DEBUG(0, ("error creating socket directory %s: %s\n",
|
||||
WINBINDD_SOCKET_DIR, sys_errlist[errno]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DEBUG(0, ("lstat failed on socket directory %s: %s\n",
|
||||
WINBINDD_SOCKET_DIR, sys_errlist[errno]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Check ownership and permission on existing directory */
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
DEBUG(0, ("socket directory %s isn't a directory\n",
|
||||
WINBINDD_SOCKET_DIR));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((st.st_uid != 0) || ((st.st_mode & 0777) != 0755)) {
|
||||
DEBUG(0, ("invalid permissions on socket directory %s\n",
|
||||
WINBINDD_SOCKET_DIR));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the socket file */
|
||||
|
||||
old_umask = umask(0);
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sock == -1) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
slprintf(path, sizeof(path), "%s/%s",
|
||||
WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
|
||||
|
||||
unlink(path);
|
||||
memset(&sunaddr, 0, sizeof(sunaddr));
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
|
||||
DEBUG(0, ("bind failed on winbind socket %s: %s\n",
|
||||
path,
|
||||
sys_errlist[errno]));
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(sock, 5) == -1) {
|
||||
DEBUG(0, ("listen failed on winbind socket %s: %s\n",
|
||||
path,
|
||||
sys_errlist[errno]));
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
umask(old_umask);
|
||||
|
||||
/* Success! */
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void process_request(struct winbindd_cli_state *state)
|
||||
{
|
||||
/* Process command */
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case WINBINDD_GETPWNAM_FROM_UID:
|
||||
state->response.result = winbindd_getpwnam_from_uid(state);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a new connection by adding it to the client connection list */
|
||||
|
||||
static void new_connection(int accept_sock)
|
||||
{
|
||||
struct sockaddr_un sunaddr;
|
||||
struct winbindd_cli_state *state;
|
||||
int len, sock;
|
||||
|
||||
/* Accept connection */
|
||||
|
||||
len = sizeof(sunaddr);
|
||||
if ((sock = accept(accept_sock, (struct sockaddr *)&sunaddr, &len))
|
||||
== -1) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(6,("accepted socket %d\n", sock));
|
||||
|
||||
/* Create new connection structure */
|
||||
|
||||
if ((state = (struct winbindd_cli_state *)
|
||||
malloc(sizeof(*state))) == NULL) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(state);
|
||||
state->sock = sock;
|
||||
|
||||
/* Add to connection list */
|
||||
|
||||
DLIST_ADD(client_list, state);
|
||||
}
|
||||
|
||||
/* Remove a client connection from client connection list */
|
||||
|
||||
static void remove_client(struct winbindd_cli_state *state)
|
||||
{
|
||||
/* It's a dead client - hold a funeral */
|
||||
|
||||
if (state != NULL) {
|
||||
|
||||
/* Close socket */
|
||||
|
||||
close(state->sock);
|
||||
|
||||
/* Free any getent state */
|
||||
|
||||
free_getent_state(state->getpwent_state);
|
||||
free_getent_state(state->getgrent_state);
|
||||
|
||||
/* Free any extra data */
|
||||
|
||||
safe_free(state->response.extra_data);
|
||||
|
||||
/* Remove from list and free */
|
||||
|
||||
DLIST_REMOVE(client_list, state);
|
||||
free(state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a complete received packet from a client */
|
||||
|
||||
static void process_packet(struct winbindd_cli_state *state)
|
||||
{
|
||||
/* Process request */
|
||||
|
||||
state->pid = state->request.pid;
|
||||
|
||||
process_request(state);
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->read_buf_len = 0;
|
||||
state->write_buf_len = sizeof(state->response);
|
||||
}
|
||||
|
||||
/* Read some data from a client connection */
|
||||
|
||||
static void client_read(struct winbindd_cli_state *state)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Read data */
|
||||
|
||||
n = read(state->sock, state->read_buf_len + (char *)&state->request,
|
||||
sizeof(state->request) - state->read_buf_len);
|
||||
|
||||
/* Read failed, kill client */
|
||||
|
||||
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"));
|
||||
|
||||
state->finished = True;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->read_buf_len += n;
|
||||
}
|
||||
|
||||
/* Write some data to a client connection */
|
||||
|
||||
static void client_write(struct winbindd_cli_state *state)
|
||||
{
|
||||
char *data;
|
||||
int n;
|
||||
|
||||
/* Write 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 {
|
||||
|
||||
/* Write response structure */
|
||||
|
||||
data = (char *)&state->response + sizeof(state->response) -
|
||||
state->write_buf_len;
|
||||
}
|
||||
|
||||
n = write(state->sock, data, state->write_buf_len);
|
||||
|
||||
/* Write failed, kill cilent */
|
||||
|
||||
if (n == -1 || n == 0) {
|
||||
|
||||
DEBUG(3,("write failed on sock %d, pid %d: %s\n",
|
||||
state->sock, state->pid,
|
||||
(n == -1) ? sys_errlist[errno] : "EOF"));
|
||||
|
||||
state->finished = True;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update client state */
|
||||
|
||||
state->write_buf_len -= n;
|
||||
|
||||
/* Have we written all data? */
|
||||
|
||||
if (state->write_buf_len == 0) {
|
||||
|
||||
/* 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 {
|
||||
|
||||
/* Start writing extra data */
|
||||
|
||||
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
|
||||
simultaneous connections while remaining impervious to many denial of
|
||||
service attacks. */
|
||||
|
||||
static void process_loop(int accept_sock)
|
||||
{
|
||||
/* We'll be doing this a lot */
|
||||
|
||||
while (1) {
|
||||
struct winbindd_cli_state *state;
|
||||
fd_set r_fds, w_fds;
|
||||
int maxfd = accept_sock, selret;
|
||||
struct timeval timeout;
|
||||
|
||||
/* do any connection establishment that is needed */
|
||||
establish_connections();
|
||||
|
||||
/* Initialise fd lists for select() */
|
||||
|
||||
FD_ZERO(&r_fds);
|
||||
FD_ZERO(&w_fds);
|
||||
FD_SET(accept_sock, &r_fds);
|
||||
|
||||
timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* Set up client readers and writers */
|
||||
|
||||
state = client_list;
|
||||
|
||||
while (state) {
|
||||
/* Dispose of client connection if it is marked as finished */
|
||||
|
||||
if (state->finished) {
|
||||
struct winbindd_cli_state *next = state->next;
|
||||
|
||||
remove_client(state);
|
||||
state = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Select requires we know the highest fd used */
|
||||
|
||||
if (state->sock > maxfd) maxfd = state->sock;
|
||||
|
||||
/* Add fd for reading */
|
||||
|
||||
if (state->read_buf_len != sizeof(state->request)) {
|
||||
FD_SET(state->sock, &r_fds);
|
||||
}
|
||||
|
||||
/* Add fd for writing */
|
||||
|
||||
if (state->write_buf_len) {
|
||||
FD_SET(state->sock, &w_fds);
|
||||
}
|
||||
|
||||
state = state->next;
|
||||
}
|
||||
|
||||
/* Check signal handling things */
|
||||
|
||||
if (flush_cache) {
|
||||
do_flush_caches();
|
||||
reload_services_file();
|
||||
flush_cache = False;
|
||||
}
|
||||
|
||||
if (print_client_info) {
|
||||
do_print_client_info();
|
||||
print_client_info = False;
|
||||
}
|
||||
|
||||
/* Call select */
|
||||
|
||||
selret = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
|
||||
|
||||
if (selret == 0) continue;
|
||||
|
||||
if ((selret == -1 && errno != EINTR) || selret == 0) {
|
||||
|
||||
/* Select error, something is badly wrong */
|
||||
|
||||
perror("select");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Create a new connection if accept_sock readable */
|
||||
|
||||
if (selret > 0) {
|
||||
|
||||
if (FD_ISSET(accept_sock, &r_fds)) {
|
||||
new_connection(accept_sock);
|
||||
}
|
||||
|
||||
/* Process activity on client connections */
|
||||
|
||||
for (state = client_list; state ; state = state->next) {
|
||||
|
||||
/* Data available for reading */
|
||||
|
||||
if (FD_ISSET(state->sock, &r_fds)) {
|
||||
|
||||
/* Read data */
|
||||
|
||||
client_read(state);
|
||||
|
||||
/* A request packet might be complete */
|
||||
|
||||
if (state->read_buf_len == sizeof(state->request)) {
|
||||
process_packet(state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Data available for writing */
|
||||
|
||||
if (FD_ISSET(state->sock, &w_fds)) {
|
||||
client_write(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Main function */
|
||||
|
||||
struct winbindd_state server_state; /* Server state information */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
extern pstring global_myname;
|
||||
extern pstring debugf;
|
||||
int accept_sock;
|
||||
BOOL interactive = False;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "i")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
interactive = True;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown option %c (%d)\n", (char)opt, opt);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise samba/rpc client stuff */
|
||||
slprintf(debugf, sizeof(debugf), "%s/log.winbindd", LOGFILEBASE);
|
||||
setup_logging("winbindd", interactive);
|
||||
reopen_logs();
|
||||
|
||||
if (!*global_myname) {
|
||||
char *p;
|
||||
|
||||
fstrcpy(global_myname, myhostname());
|
||||
p = strchr(global_myname, '.');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TimeInit();
|
||||
charset_initialise();
|
||||
codepage_initialise(lp_client_code_page());
|
||||
|
||||
if (!lp_load(CONFIGFILE, True, False, False)) {
|
||||
DEBUG(0, ("error opening config file\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!interactive) {
|
||||
become_daemon();
|
||||
}
|
||||
load_interfaces();
|
||||
|
||||
secrets_init();
|
||||
|
||||
ZERO_STRUCT(server_state);
|
||||
|
||||
/* Winbind daemon initialisation */
|
||||
if (!winbindd_param_init()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!winbindd_idmap_init()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
winbindd_cache_init();
|
||||
|
||||
/* Setup signal handlers */
|
||||
|
||||
CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
|
||||
CatchSignal(SIGQUIT, termination_handler);
|
||||
CatchSignal(SIGTERM, termination_handler);
|
||||
|
||||
CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
|
||||
|
||||
CatchSignal(SIGUSR1, sigusr1_handler); /* Debugging sigs */
|
||||
CatchSignal(SIGHUP, sighup_handler);
|
||||
|
||||
/* Create UNIX domain socket */
|
||||
|
||||
if ((accept_sock = create_sock()) == -1) {
|
||||
DEBUG(0, ("failed to create socket\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Loop waiting for requests */
|
||||
|
||||
process_loop(accept_sock);
|
||||
|
||||
return 0;
|
||||
}
|
106
source/nsswitch/winbindd.h
Normal file
106
source/nsswitch/winbindd.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _WINBINDD_H
|
||||
#define _WINBINDD_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "nterr.h"
|
||||
|
||||
#include "winbindd_ntdom.h"
|
||||
|
||||
/* Naughty global stuff */
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
/* Client state structure */
|
||||
|
||||
struct winbindd_cli_state {
|
||||
struct winbindd_cli_state *prev, *next; /* Linked list pointers */
|
||||
int sock; /* Open socket from client */
|
||||
pid_t pid; /* pid of client */
|
||||
int read_buf_len, write_buf_len; /* Indexes in request/response */
|
||||
BOOL finished; /* Can delete from list */
|
||||
BOOL write_extra_data; /* Write extra_data field */
|
||||
struct winbindd_request request; /* Request from client */
|
||||
struct winbindd_response response; /* Respose to client */
|
||||
struct getent_state *getpwent_state; /* State for getpwent() */
|
||||
struct getent_state *getgrent_state; /* State for getgrent() */
|
||||
};
|
||||
|
||||
struct getent_state {
|
||||
struct getent_state *prev, *next;
|
||||
struct acct_info *sam_entries;
|
||||
uint32 sam_entry_index, num_sam_entries;
|
||||
struct winbindd_domain *domain;
|
||||
BOOL got_sam_entries;
|
||||
};
|
||||
|
||||
/* Server state structure */
|
||||
|
||||
struct winbindd_state {
|
||||
/* Netbios name of PDC */
|
||||
fstring controller;
|
||||
|
||||
/* User and group id pool */
|
||||
uid_t uid_low, uid_high; /* Range of uids to allocate */
|
||||
gid_t gid_low, gid_high; /* Range of gids to allocate */
|
||||
|
||||
/* Cached handle to lsa pipe */
|
||||
POLICY_HND lsa_handle;
|
||||
BOOL lsa_handle_open;
|
||||
BOOL pwdb_initialised;
|
||||
};
|
||||
|
||||
extern struct winbindd_state server_state; /* Server information */
|
||||
|
||||
/* Structures to hold per domain information */
|
||||
|
||||
struct winbindd_domain {
|
||||
|
||||
/* Domain information */
|
||||
|
||||
fstring name; /* Domain name */
|
||||
fstring controller; /* NetBIOS name of DC */
|
||||
|
||||
DOM_SID sid; /* SID for this domain */
|
||||
BOOL got_domain_info; /* Got controller and sid */
|
||||
|
||||
/* Cached handles to samr pipe */
|
||||
POLICY_HND sam_handle, sam_dom_handle;
|
||||
BOOL sam_handle_open, sam_dom_handle_open;
|
||||
|
||||
struct winbindd_domain *prev, *next; /* Linked list info */
|
||||
};
|
||||
|
||||
extern struct winbindd_domain *domain_list; /* List of domains we know */
|
||||
|
||||
#include "winbindd_proto.h"
|
||||
|
||||
#include "rpc_parse.h"
|
||||
|
||||
#define WINBINDD_ESTABLISH_LOOP 30
|
||||
#define DOM_SEQUENCE_NONE ((uint32)-1)
|
||||
|
||||
#endif /* _WINBINDD_H */
|
416
source/nsswitch/winbindd_cache.c
Normal file
416
source/nsswitch/winbindd_cache.c
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon - caching related functions
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
|
||||
#define CACHE_TYPE_USER "USR"
|
||||
#define CACHE_TYPE_GROUP "GRP"
|
||||
|
||||
/* Initialise caching system */
|
||||
|
||||
static TDB_CONTEXT *cache_tdb;
|
||||
|
||||
struct cache_rec {
|
||||
uint32 seq_num;
|
||||
time_t mod_time;
|
||||
};
|
||||
|
||||
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))) {
|
||||
DEBUG(0, ("Unable to open tdb cache - user and group caching "
|
||||
"disabled\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/* get the domain sequence number, possibly re-fetching */
|
||||
static uint32 cached_sequence_number(char *domain_name)
|
||||
{
|
||||
fstring keystr;
|
||||
TDB_DATA dbuf;
|
||||
struct cache_rec rec;
|
||||
time_t t = time(NULL);
|
||||
|
||||
slprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
|
||||
dbuf = tdb_fetch_by_string(cache_tdb, keystr);
|
||||
if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
|
||||
goto refetch;
|
||||
}
|
||||
memcpy(&rec, dbuf.dptr, sizeof(rec));
|
||||
free(dbuf.dptr);
|
||||
|
||||
if (t < (rec.mod_time + lp_winbind_cache_time())) {
|
||||
DEBUG(4,("cached sequence number for %s is %u\n",
|
||||
domain_name, (unsigned)rec.seq_num));
|
||||
return rec.seq_num;
|
||||
}
|
||||
|
||||
refetch:
|
||||
rec.seq_num = domain_sequence_number(domain_name);
|
||||
rec.mod_time = t;
|
||||
tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
|
||||
|
||||
return rec.seq_num;
|
||||
}
|
||||
|
||||
/* Check whether a seq_num for a cached item has expired */
|
||||
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));
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
static void set_cache_sequence_number(char *domain_name, char *cache_type, char *subkey)
|
||||
{
|
||||
fstring keystr;
|
||||
slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
|
||||
domain_name, cache_type, subkey?subkey:"");
|
||||
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)
|
||||
{
|
||||
fstring keystr;
|
||||
uint32 seq_num;
|
||||
slprintf(keystr,sizeof(keystr),"CACHESEQ %s/%s/%s",
|
||||
domain_name, cache_type, subkey?subkey:"");
|
||||
seq_num = (uint32)tdb_get_int(cache_tdb, keystr);
|
||||
DEBUG(4,("%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)
|
||||
{
|
||||
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));
|
||||
|
||||
/* Store data as a mega-huge chunk in the tdb */
|
||||
slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
|
||||
domain_name);
|
||||
|
||||
tdb_store_by_string(cache_tdb, keystr,
|
||||
sam_entries, sizeof(struct acct_info) * num_sam_entries);
|
||||
|
||||
/* Stamp cache with current seq number */
|
||||
set_cache_sequence_number(domain_name, cache_type, NULL);
|
||||
}
|
||||
|
||||
/* Fill the user cache with supplied data */
|
||||
|
||||
void winbindd_fill_user_cache(char *domain_name,
|
||||
struct acct_info *sam_entries,
|
||||
int num_sam_entries)
|
||||
{
|
||||
fill_cache(domain_name, CACHE_TYPE_USER, sam_entries, num_sam_entries);
|
||||
}
|
||||
|
||||
/* Fill the group cache with supplied data */
|
||||
|
||||
void winbindd_fill_group_cache(char *domain_name,
|
||||
struct acct_info *sam_entries,
|
||||
int num_sam_entries)
|
||||
{
|
||||
fill_cache(domain_name, CACHE_TYPE_GROUP, sam_entries, num_sam_entries);
|
||||
}
|
||||
|
||||
static void fill_cache_entry(char *domain, char *name, void *buf, int len)
|
||||
{
|
||||
fstring keystr;
|
||||
|
||||
/* Create key for store */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s", domain, name);
|
||||
|
||||
DEBUG(4, ("filling cache entry %s\n", keystr));
|
||||
|
||||
/* 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,
|
||||
struct winbindd_pw *pw)
|
||||
{
|
||||
if (lp_winbind_cache_time() == 0) return;
|
||||
|
||||
fill_cache_entry(domain, 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,
|
||||
struct winbindd_pw *pw)
|
||||
{
|
||||
fstring uidstr;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return;
|
||||
|
||||
slprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
|
||||
fill_cache_entry(domain, 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,
|
||||
struct winbindd_gr *gr, void *extra_data,
|
||||
int extra_data_len)
|
||||
{
|
||||
fstring keystr;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return;
|
||||
|
||||
/* Fill group data */
|
||||
fill_cache_entry(domain, group_name, gr, sizeof(struct winbindd_gr));
|
||||
|
||||
/* Fill extra data */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s DATA", 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,
|
||||
struct winbindd_gr *gr, void *extra_data,
|
||||
int extra_data_len)
|
||||
{
|
||||
fstring keystr;
|
||||
fstring gidstr;
|
||||
|
||||
slprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return;
|
||||
|
||||
/* Fill group data */
|
||||
fill_cache_entry(domain, gidstr, gr, sizeof(struct winbindd_gr));
|
||||
|
||||
/* Fill extra data */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s DATA", domain, gidstr);
|
||||
tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
|
||||
|
||||
set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
TDB_DATA data;
|
||||
fstring keystr;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return False;
|
||||
|
||||
/* Parameter check */
|
||||
if (!sam_entries || !num_sam_entries) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Check cache data is current */
|
||||
if (cache_domain_expired(domain_name,
|
||||
get_cache_sequence_number(domain_name, cache_type, NULL))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Create key */
|
||||
slprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
|
||||
domain_name);
|
||||
|
||||
/* Fetch cache information */
|
||||
data = tdb_fetch_by_string(cache_tdb, keystr);
|
||||
|
||||
if (!data.dptr) return False;
|
||||
|
||||
/* Copy across cached data. We can save a memcpy() by directly
|
||||
assigning the data.dptr to the sam_entries pointer. It will
|
||||
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));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Return cached entries for a domain. Return false if there are no cached
|
||||
entries, or the cached information has expired for the domain. */
|
||||
|
||||
BOOL winbindd_fetch_user_cache(char *domain_name,
|
||||
struct acct_info **sam_entries,
|
||||
int *num_entries)
|
||||
{
|
||||
return fetch_cache(domain_name, CACHE_TYPE_USER, sam_entries,
|
||||
num_entries);
|
||||
}
|
||||
|
||||
/* Return cached entries for a domain. Return false if there are no cached
|
||||
entries, or the cached information has expired for the domain. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static BOOL fetch_cache_entry(char *domain, char *name, void *buf, int len)
|
||||
{
|
||||
TDB_DATA data;
|
||||
fstring keystr;
|
||||
|
||||
/* Create key for lookup */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s", 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);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Fetch an individual user cache entry */
|
||||
BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
|
||||
struct winbindd_pw *pw)
|
||||
{
|
||||
uint32 seq_num;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return False;
|
||||
|
||||
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, user, pw, sizeof(struct winbindd_pw));
|
||||
}
|
||||
|
||||
/* Fetch an individual uid cache entry */
|
||||
BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
|
||||
struct winbindd_pw *pw)
|
||||
{
|
||||
fstring uidstr;
|
||||
uint32 seq_num;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return False;
|
||||
|
||||
slprintf(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, uidstr, pw, sizeof(struct winbindd_pw));
|
||||
}
|
||||
|
||||
/* Fetch an individual group cache entry. This function differs from the
|
||||
user cache code as we need to store the group membership data. */
|
||||
|
||||
BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
|
||||
struct winbindd_gr *gr,
|
||||
void **extra_data, int *extra_data_len)
|
||||
{
|
||||
TDB_DATA data;
|
||||
fstring keystr;
|
||||
uint32 seq_num;
|
||||
|
||||
if (lp_winbind_cache_time() == 0) return False;
|
||||
|
||||
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, group, gr, sizeof(struct winbindd_gr))) return False;
|
||||
|
||||
/* Fetch extra data */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s DATA", domain_name, group);
|
||||
data = tdb_fetch_by_string(cache_tdb, keystr);
|
||||
|
||||
if (!data.dptr) return False;
|
||||
|
||||
/* Extra data freed when data has been sent */
|
||||
if (extra_data) *extra_data = data.dptr;
|
||||
if (extra_data_len) *extra_data_len = data.dsize;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/* Fetch an individual gid cache entry. This function differs from the
|
||||
user cache code as we need to store the group membership data. */
|
||||
|
||||
BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
|
||||
struct winbindd_gr *gr,
|
||||
void **extra_data, int *extra_data_len)
|
||||
{
|
||||
TDB_DATA data;
|
||||
fstring keystr;
|
||||
fstring gidstr;
|
||||
uint32 seq_num;
|
||||
|
||||
slprintf(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);
|
||||
if (cache_domain_expired(domain_name, seq_num)) return False;
|
||||
|
||||
/* Fetch group data */
|
||||
if (!fetch_cache_entry(domain_name, gidstr, gr, sizeof(struct winbindd_gr))) return False;
|
||||
|
||||
/* Fetch extra data */
|
||||
slprintf(keystr, sizeof(keystr), "%s/%s DATA", domain_name, gidstr);
|
||||
data = tdb_fetch_by_string(cache_tdb, keystr);
|
||||
if (!data.dptr) return False;
|
||||
|
||||
/* Extra data freed when data has been sent */
|
||||
if (extra_data) *extra_data = data.dptr;
|
||||
if (extra_data_len) *extra_data_len = data.dsize;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Flush cache data - easiest to just reopen the tdb */
|
||||
void winbindd_flush_cache(void)
|
||||
{
|
||||
tdb_close(cache_tdb);
|
||||
winbindd_cache_init();
|
||||
}
|
763
source/nsswitch/winbindd_group.c
Normal file
763
source/nsswitch/winbindd_group.c
Normal file
@ -0,0 +1,763 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
|
||||
/* Fill a grent structure from various other information */
|
||||
|
||||
static void winbindd_fill_grent(struct winbindd_gr *gr, char *gr_name,
|
||||
gid_t unix_gid)
|
||||
{
|
||||
/* Fill in uid/gid */
|
||||
|
||||
gr->gr_gid = unix_gid;
|
||||
|
||||
/* Group name and password */
|
||||
|
||||
safe_strcpy(gr->gr_name, gr_name, sizeof(gr->gr_name) - 1);
|
||||
safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
|
||||
}
|
||||
|
||||
/* Fill in group membership */
|
||||
|
||||
struct grent_mem_group {
|
||||
uint32 rid;
|
||||
enum SID_NAME_USE name_type;
|
||||
fstring domain_name;
|
||||
struct winbindd_domain *domain;
|
||||
struct grent_mem_group *prev, *next;
|
||||
};
|
||||
|
||||
struct grent_mem_list {
|
||||
fstring name;
|
||||
struct grent_mem_list *prev, *next;
|
||||
};
|
||||
|
||||
/* Name comparison function for qsort() */
|
||||
|
||||
static int name_comp(struct grent_mem_list *n1, struct grent_mem_list *n2)
|
||||
{
|
||||
/* Silly cases */
|
||||
|
||||
if (!n1 && !n2) return 0;
|
||||
if (!n1) return -1;
|
||||
if (!n2) return 1;
|
||||
|
||||
return strcmp(n1->name, n2->name);
|
||||
}
|
||||
|
||||
static struct grent_mem_list *sort_groupmem_list(struct grent_mem_list *list,
|
||||
int num_gr_mem)
|
||||
{
|
||||
struct grent_mem_list *groupmem_array, *temp;
|
||||
int i;
|
||||
|
||||
/* Allocate and zero an array to hold sorted entries */
|
||||
|
||||
if ((groupmem_array = malloc(num_gr_mem *
|
||||
sizeof(struct grent_mem_list))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset((char *)groupmem_array, 0, num_gr_mem *
|
||||
sizeof(struct grent_mem_list));
|
||||
|
||||
/* Copy list to array */
|
||||
|
||||
for(temp = list, i = 0; temp && i < num_gr_mem; temp = temp->next, i++) {
|
||||
fstrcpy(groupmem_array[i].name, temp->name);
|
||||
}
|
||||
|
||||
/* Sort array */
|
||||
|
||||
qsort(groupmem_array, num_gr_mem, sizeof(struct grent_mem_list),
|
||||
name_comp);
|
||||
|
||||
/* Fix up resulting array to a linked list and return it */
|
||||
|
||||
for(i = 0; i < num_gr_mem; i++) {
|
||||
|
||||
/* Fix up previous link */
|
||||
|
||||
if (i != 0) {
|
||||
groupmem_array[i].prev = &groupmem_array[i - 1];
|
||||
}
|
||||
|
||||
/* Fix up next link */
|
||||
|
||||
if (i != (num_gr_mem - 1)) {
|
||||
groupmem_array[i].next = &groupmem_array[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return groupmem_array;
|
||||
}
|
||||
|
||||
static BOOL winbindd_fill_grent_mem(struct winbindd_domain *domain,
|
||||
uint32 group_rid,
|
||||
enum SID_NAME_USE group_name_type,
|
||||
struct winbindd_response *response)
|
||||
{
|
||||
struct grent_mem_group *done_groups = NULL, *todo_groups = NULL;
|
||||
struct grent_mem_group *temp_group;
|
||||
struct grent_mem_list *groupmem_list = NULL;
|
||||
struct winbindd_gr *gr;
|
||||
|
||||
if (response) {
|
||||
gr = &response->data.gr;
|
||||
} else {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Initialise group membership information */
|
||||
|
||||
gr->num_gr_mem = 0;
|
||||
|
||||
/* Add first group to todo_groups list */
|
||||
|
||||
if ((temp_group =
|
||||
(struct grent_mem_group *)malloc(sizeof(*temp_group))) == NULL) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(temp_group);
|
||||
|
||||
temp_group->rid = group_rid;
|
||||
temp_group->name_type = group_name_type;
|
||||
temp_group->domain = domain;
|
||||
fstrcpy(temp_group->domain_name, domain->name);
|
||||
|
||||
DLIST_ADD(todo_groups, temp_group);
|
||||
|
||||
/* Iterate over all groups to find members of */
|
||||
|
||||
while(todo_groups != NULL) {
|
||||
struct grent_mem_group *current_group = todo_groups;
|
||||
uint32 num_names = 0, *rid_mem = NULL;
|
||||
enum SID_NAME_USE *name_types = NULL;
|
||||
|
||||
DOM_SID **sids = NULL;
|
||||
char **names = NULL;
|
||||
BOOL done_group;
|
||||
int i;
|
||||
|
||||
/* Check we haven't looked up this group before */
|
||||
|
||||
done_group = 0;
|
||||
|
||||
for (temp_group = done_groups; temp_group != NULL;
|
||||
temp_group = temp_group->next) {
|
||||
|
||||
if ((temp_group->rid == current_group->rid) &&
|
||||
(strcmp(temp_group->domain_name,
|
||||
current_group->domain_name) == 0)) {
|
||||
|
||||
done_group = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (done_group) goto cleanup;
|
||||
|
||||
/* Lookup group membership for the current group */
|
||||
|
||||
if (current_group->name_type == SID_NAME_DOM_GRP) {
|
||||
|
||||
if (!winbindd_lookup_groupmem(current_group->domain,
|
||||
current_group->rid, &num_names,
|
||||
&rid_mem, &names, &name_types)) {
|
||||
|
||||
DEBUG(1, ("fill_grent_mem(): could not lookup membership "
|
||||
"for group rid %d in domain %s\n",
|
||||
current_group->rid,
|
||||
current_group->domain->name));
|
||||
|
||||
/* Exit if we cannot lookup the membership for the group
|
||||
this function was called to look at */
|
||||
|
||||
if (current_group->rid == group_rid) {
|
||||
return False;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_group->name_type == SID_NAME_ALIAS) {
|
||||
|
||||
if (!winbindd_lookup_aliasmem(current_group->domain,
|
||||
current_group->rid, &num_names,
|
||||
&sids, &names, &name_types)) {
|
||||
|
||||
DEBUG(1, ("fill_grent_mem(): group rid %d not a local group\n",
|
||||
group_rid));
|
||||
|
||||
/* Exit if we cannot lookup the membership for the group
|
||||
this function was called to look at */
|
||||
|
||||
if (current_group->rid == group_rid) {
|
||||
return False;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now for each member of the group, add it to the group list if it
|
||||
is a user, otherwise push it onto the todo_group list if it is a
|
||||
group or an alias. */
|
||||
|
||||
for (i = 0; i < num_names; i++) {
|
||||
enum SID_NAME_USE name_type;
|
||||
fstring name_part1, name_part2;
|
||||
char *name_dom, *name_user, *the_name;
|
||||
struct winbindd_domain *name_domain;
|
||||
|
||||
/* Lookup name */
|
||||
|
||||
ZERO_STRUCT(name_part1);
|
||||
ZERO_STRUCT(name_part2);
|
||||
|
||||
the_name = names[i];
|
||||
parse_domain_user(the_name, name_part1, name_part2);
|
||||
|
||||
if (strcmp(name_part1, "") != 0) {
|
||||
name_dom = name_part1;
|
||||
name_user = name_part2;
|
||||
|
||||
if ((name_domain = find_domain_from_name(name_dom)) == NULL) {
|
||||
DEBUG(0, ("unable to look up domain record for domain "
|
||||
"%s\n", name_dom));
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
name_dom = current_group->domain->name;
|
||||
name_user = name_part2;
|
||||
name_domain = current_group->domain;
|
||||
}
|
||||
|
||||
if (winbindd_lookup_sid_by_name(name_domain, name_user, NULL,
|
||||
&name_type) == WINBINDD_OK) {
|
||||
|
||||
/* Check name type */
|
||||
|
||||
if (name_type == SID_NAME_USER) {
|
||||
struct grent_mem_list *entry;
|
||||
|
||||
/* Add to group membership list */
|
||||
|
||||
if ((entry = (struct grent_mem_list *)
|
||||
malloc(sizeof(*entry))) != NULL) {
|
||||
|
||||
/* Create name */
|
||||
slprintf(entry->name, sizeof(entry->name),
|
||||
"%s/%s", name_dom, name_user);
|
||||
|
||||
/* Add to list */
|
||||
|
||||
DLIST_ADD(groupmem_list, entry);
|
||||
gr->num_gr_mem++;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct grent_mem_group *todo_group;
|
||||
DOM_SID todo_sid;
|
||||
uint32 todo_rid;
|
||||
|
||||
/* Add group to todo list */
|
||||
|
||||
if (winbindd_lookup_sid_by_name(name_domain, names[i],
|
||||
&todo_sid, &name_type)
|
||||
== WINBINDD_OK) {
|
||||
|
||||
/* Fill in group entry */
|
||||
|
||||
sid_split_rid(&todo_sid, &todo_rid);
|
||||
|
||||
if ((todo_group = (struct grent_mem_group *)
|
||||
malloc(sizeof(*todo_group))) != NULL) {
|
||||
|
||||
ZERO_STRUCTP(todo_group);
|
||||
|
||||
todo_group->rid = todo_rid;
|
||||
todo_group->name_type = name_type;
|
||||
todo_group->domain = name_domain;
|
||||
|
||||
fstrcpy(todo_group->domain_name, name_dom);
|
||||
|
||||
DLIST_ADD(todo_groups, todo_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Remove group from todo list and add to done_groups list */
|
||||
|
||||
DLIST_REMOVE(todo_groups, current_group);
|
||||
DLIST_ADD(done_groups, current_group);
|
||||
|
||||
/* Free memory allocated in winbindd_lookup_{alias,group}mem() */
|
||||
|
||||
safe_free(name_types);
|
||||
safe_free(rid_mem);
|
||||
|
||||
free_char_array(num_names, names);
|
||||
free_sid_array(num_names, sids);
|
||||
}
|
||||
|
||||
/* Free done groups list */
|
||||
|
||||
temp_group = done_groups;
|
||||
|
||||
if (temp_group != NULL) {
|
||||
while (temp_group != NULL) {
|
||||
struct grent_mem_group *next;
|
||||
|
||||
DLIST_REMOVE(done_groups, temp_group);
|
||||
next = temp_group->next;
|
||||
|
||||
free(temp_group);
|
||||
temp_group = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove duplicates from group member list. */
|
||||
|
||||
if (gr->num_gr_mem > 0) {
|
||||
struct grent_mem_list *sorted_groupmem_list, *temp;
|
||||
int extra_data_len = 0;
|
||||
fstring prev_name;
|
||||
char *head;
|
||||
|
||||
/* Sort list */
|
||||
|
||||
sorted_groupmem_list = sort_groupmem_list(groupmem_list,
|
||||
gr->num_gr_mem);
|
||||
/* Remove duplicates by iteration */
|
||||
|
||||
fstrcpy(prev_name, "");
|
||||
|
||||
for(temp = sorted_groupmem_list; temp; temp = temp->next) {
|
||||
if (strequal(temp->name, prev_name)) {
|
||||
|
||||
/* Got a duplicate name - delete it. Don't panic as we're
|
||||
only adjusting the prev and next pointers so memory
|
||||
allocation is not messed up. */
|
||||
|
||||
DLIST_REMOVE(sorted_groupmem_list, temp);
|
||||
gr->num_gr_mem--;
|
||||
|
||||
} else {
|
||||
|
||||
/* Got a unique name - count how long it is */
|
||||
|
||||
extra_data_len += strlen(temp->name) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
extra_data_len++; /* Don't forget null a terminator */
|
||||
|
||||
/* Convert sorted list into extra data field to send back to ntdom
|
||||
client. Add one to extra_data_len for null termination */
|
||||
|
||||
if ((response->extra_data = malloc(extra_data_len))) {
|
||||
|
||||
/* Initialise extra data */
|
||||
|
||||
memset(response->extra_data, 0, extra_data_len);
|
||||
|
||||
head = response->extra_data;
|
||||
|
||||
/* Fill in extra data */
|
||||
|
||||
for(temp = sorted_groupmem_list; temp; temp = temp->next) {
|
||||
int len = strlen(temp->name) + 1;
|
||||
|
||||
safe_strcpy(head, temp->name, len);
|
||||
head[len - 1] = ',';
|
||||
head += len;
|
||||
}
|
||||
|
||||
*head = '\0';
|
||||
|
||||
/* Update response length */
|
||||
|
||||
response->length = sizeof(struct winbindd_response) +
|
||||
extra_data_len;
|
||||
}
|
||||
|
||||
/* Free memory for sorted_groupmem_list. It was allocated as an
|
||||
array in sort_groupmem_list() so can be freed in one go. */
|
||||
|
||||
free(sorted_groupmem_list);
|
||||
|
||||
/* Free groupmem_list */
|
||||
|
||||
temp = groupmem_list;
|
||||
|
||||
while (temp != NULL) {
|
||||
struct grent_mem_list *next;
|
||||
|
||||
DLIST_REMOVE(groupmem_list, temp);
|
||||
next = temp->next;
|
||||
|
||||
free(temp);
|
||||
temp = next;
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Return a group structure from a group name */
|
||||
|
||||
enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state)
|
||||
{
|
||||
DOM_SID group_sid;
|
||||
struct winbindd_domain *domain;
|
||||
enum SID_NAME_USE name_type;
|
||||
uint32 group_rid;
|
||||
fstring name_domain, name_group, name;
|
||||
char *tmp;
|
||||
gid_t gid;
|
||||
int extra_data_len;
|
||||
|
||||
/* Parse domain and groupname */
|
||||
|
||||
memset(name_group, 0, sizeof(fstring));
|
||||
|
||||
tmp = state->request.data.groupname;
|
||||
parse_domain_user(tmp, name_domain, name_group);
|
||||
|
||||
/* Reject names that don't have a domain - i.e name_domain contains the
|
||||
entire name. */
|
||||
|
||||
if (strequal(name_group, "")) {
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Get info for the domain */
|
||||
|
||||
if ((domain = find_domain_from_name(name_domain)) == NULL) {
|
||||
DEBUG(0, ("getgrname_from_group(): could not get domain sid for "
|
||||
"domain %s\n", name_domain));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Check for cached user entry */
|
||||
|
||||
if (winbindd_fetch_group_cache_entry(name_domain, name_group,
|
||||
&state->response.data.gr,
|
||||
&state->response.extra_data,
|
||||
&extra_data_len)) {
|
||||
state->response.length += extra_data_len;
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
slprintf(name, sizeof(name), "%s\\%s", name_domain, name_group);
|
||||
|
||||
/* Get rid and name type from name */
|
||||
|
||||
if (!winbindd_lookup_sid_by_name(domain, name, &group_sid,
|
||||
&name_type)) {
|
||||
DEBUG(1, ("group %s in domain %s does not exist\n", name_group,
|
||||
name_domain));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
|
||||
DEBUG(1, ("from_group: name '%s' is not a local or domain group: %d\n",
|
||||
name_group, name_type));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Fill in group structure */
|
||||
|
||||
sid_split_rid(&group_sid, &group_rid);
|
||||
|
||||
if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
|
||||
DEBUG(1, ("error sursing unix gid for sid\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
winbindd_fill_grent(&state->response.data.gr,
|
||||
state->request.data.groupname, gid);
|
||||
|
||||
if (!winbindd_fill_grent_mem(domain, group_rid, name_type,
|
||||
&state->response)) {
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Update cached group info */
|
||||
|
||||
winbindd_fill_group_cache_entry(name_domain, name_group,
|
||||
&state->response.data.gr,
|
||||
state->response.extra_data,
|
||||
state->response.length -
|
||||
sizeof(struct winbindd_response));
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Return a group structure from a gid number */
|
||||
|
||||
enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
|
||||
*state)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
DOM_SID group_sid;
|
||||
enum SID_NAME_USE name_type;
|
||||
fstring group_name;
|
||||
uint32 group_rid;
|
||||
int extra_data_len;
|
||||
|
||||
/* Get rid from gid */
|
||||
if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid, &group_rid,
|
||||
&domain)) {
|
||||
DEBUG(1, ("Could not convert gid %d to rid\n",
|
||||
state->request.data.gid));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* try a cached entry */
|
||||
if (winbindd_fetch_gid_cache_entry(domain->name, state->request.data.gid,
|
||||
&state->response.data.gr,
|
||||
&state->response.extra_data,
|
||||
&extra_data_len)) {
|
||||
state->response.length += extra_data_len;
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Get sid from gid */
|
||||
|
||||
sid_copy(&group_sid, &domain->sid);
|
||||
sid_append_rid(&group_sid, group_rid);
|
||||
|
||||
if (!winbindd_lookup_name_by_sid(domain, &group_sid, group_name,
|
||||
&name_type)) {
|
||||
DEBUG(1, ("Could not lookup sid\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
string_sub(group_name, "\\", "/", sizeof(fstring));
|
||||
|
||||
if (!((name_type == SID_NAME_ALIAS) || (name_type == SID_NAME_DOM_GRP))) {
|
||||
DEBUG(1, ("from_gid: name '%s' is not a local or domain group: %d\n",
|
||||
group_name, name_type));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Fill in group structure */
|
||||
|
||||
winbindd_fill_grent(&state->response.data.gr, group_name,
|
||||
state->request.data.gid);
|
||||
|
||||
if (!winbindd_fill_grent_mem(domain, group_rid, name_type,
|
||||
&state->response)) {
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Update cached group info */
|
||||
winbindd_fill_gid_cache_entry(domain->name, state->request.data.gid,
|
||||
&state->response.data.gr,
|
||||
state->response.extra_data,
|
||||
state->response.length -
|
||||
sizeof(struct winbindd_response));
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* set/get/endgrent functions
|
||||
*/
|
||||
|
||||
/* "Rewind" file pointer for group database enumeration */
|
||||
|
||||
enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *tmp;
|
||||
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
/* Free old static data if it exists */
|
||||
|
||||
if (state->getgrent_state != NULL) {
|
||||
free_getent_state(state->getgrent_state);
|
||||
state->getgrent_state = NULL;
|
||||
}
|
||||
|
||||
/* Create sam pipes for each domain we know about */
|
||||
|
||||
for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
|
||||
struct getent_state *domain_state;
|
||||
|
||||
/* Skip domains other than WINBINDD_DOMAIN environment variable */
|
||||
|
||||
if ((strcmp(state->request.domain, "") != 0) &&
|
||||
(strcmp(state->request.domain, tmp->name) != 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create a state record for this domain */
|
||||
|
||||
if ((domain_state = (struct getent_state *)
|
||||
malloc(sizeof(struct getent_state))) == NULL) {
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(domain_state);
|
||||
|
||||
/* Add to list of open domains */
|
||||
|
||||
domain_state->domain = tmp;
|
||||
DLIST_ADD(state->getgrent_state, domain_state);
|
||||
}
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Close file pointer to ntdom group database */
|
||||
|
||||
enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
|
||||
{
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
free_getent_state(state->getgrent_state);
|
||||
state->getgrent_state = NULL;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Fetch next group entry from netdom database */
|
||||
|
||||
enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
|
||||
{
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
/* Process the current head of the getent_state list */
|
||||
|
||||
while(state->getgrent_state != NULL) {
|
||||
struct getent_state *ent = state->getgrent_state;
|
||||
|
||||
/* Get list of entries if we haven't already got them */
|
||||
|
||||
if (!ent->got_sam_entries) {
|
||||
uint32 status, start_ndx = 0, start_ndx2 = 0;
|
||||
|
||||
if (!winbindd_fetch_group_cache(ent->domain->name,
|
||||
&ent->sam_entries,
|
||||
&ent->num_sam_entries)) {
|
||||
|
||||
/* Fetch group entries */
|
||||
|
||||
if (!domain_handles_open(ent->domain)) goto cleanup;
|
||||
|
||||
/* Enumerate domain groups */
|
||||
|
||||
do {
|
||||
status =
|
||||
samr_enum_dom_groups(&ent->domain->sam_dom_handle,
|
||||
&start_ndx, 0x100000,
|
||||
&ent->sam_entries,
|
||||
&ent->num_sam_entries);
|
||||
} while (status == STATUS_MORE_ENTRIES);
|
||||
|
||||
/* Enumerate domain aliases */
|
||||
|
||||
do {
|
||||
status =
|
||||
samr_enum_dom_aliases(&ent->domain->sam_dom_handle,
|
||||
&start_ndx2, 0x100000,
|
||||
&ent->sam_entries,
|
||||
&ent->num_sam_entries);
|
||||
} while (status == STATUS_MORE_ENTRIES);
|
||||
|
||||
/* Fill cache with received entries */
|
||||
|
||||
winbindd_fill_group_cache(ent->domain->name, ent->sam_entries,
|
||||
ent->num_sam_entries);
|
||||
}
|
||||
|
||||
ent->got_sam_entries = True;
|
||||
}
|
||||
|
||||
/* Send back a group */
|
||||
|
||||
while (ent->sam_entry_index < ent->num_sam_entries) {
|
||||
enum winbindd_result result;
|
||||
fstring domain_group_name;
|
||||
char *group_name = (ent->sam_entries)
|
||||
[ent->sam_entry_index].acct_name;
|
||||
|
||||
/* Prepend domain to name */
|
||||
|
||||
slprintf(domain_group_name, sizeof(domain_group_name),
|
||||
"%s/%s", ent->domain->name, group_name);
|
||||
|
||||
/* Get group entry from group name */
|
||||
|
||||
fstrcpy(state->request.data.groupname, domain_group_name);
|
||||
result = winbindd_getgrnam_from_group(state);
|
||||
|
||||
ent->sam_entry_index++;
|
||||
|
||||
if (result == WINBINDD_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Try next group */
|
||||
|
||||
DEBUG(1, ("could not getgrnam_from_group for group name %s\n",
|
||||
domain_group_name));
|
||||
}
|
||||
|
||||
/* We've exhausted all users for this pipe - close it down and
|
||||
start on the next one. */
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Free mallocated memory for sam entries. The data stored here
|
||||
may have been allocated from the cache. */
|
||||
|
||||
if (ent->sam_entries != NULL) free(ent->sam_entries);
|
||||
ent->sam_entries = NULL;
|
||||
|
||||
/* Free state information for this domain */
|
||||
|
||||
{
|
||||
struct getent_state *old_ent;
|
||||
|
||||
old_ent = state->getgrent_state;
|
||||
DLIST_REMOVE(state->getgrent_state, state->getgrent_state);
|
||||
free(old_ent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Out of pipes so we're done */
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
235
source/nsswitch/winbindd_idmap.c
Normal file
235
source/nsswitch/winbindd_idmap.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon - user related function
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
|
||||
/* High water mark keys */
|
||||
|
||||
#define HWM_GROUP "GROUP HWM"
|
||||
#define HWM_USER "USER HWM"
|
||||
|
||||
/* Globals */
|
||||
|
||||
static TDB_CONTEXT *idmap_tdb;
|
||||
|
||||
/* Allocate either a user or group id from the pool */
|
||||
|
||||
static BOOL allocate_id(int *id, BOOL isgroup)
|
||||
{
|
||||
int hwm;
|
||||
|
||||
/* Get current high water mark */
|
||||
|
||||
if ((hwm = tdb_get_int(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER)) == -1) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Return next available uid in list */
|
||||
|
||||
if ((isgroup && (hwm > server_state.gid_high)) ||
|
||||
(!isgroup && (hwm > server_state.uid_high))) {
|
||||
DEBUG(0, ("winbind %sid range full!\n", isgroup ? "g" : "u"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
*id = hwm;
|
||||
}
|
||||
|
||||
hwm++;
|
||||
|
||||
/* Store new high water mark */
|
||||
|
||||
tdb_store_int(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Get an id from a rid */
|
||||
|
||||
static BOOL get_id_from_rid(char *domain_name, uint32 rid, int *id,
|
||||
BOOL isgroup)
|
||||
{
|
||||
TDB_DATA data, key;
|
||||
fstring keystr;
|
||||
BOOL result;
|
||||
|
||||
/* Check if rid is present in database */
|
||||
|
||||
slprintf(keystr, sizeof(keystr), "%s/%d", domain_name, rid);
|
||||
|
||||
key.dptr = keystr;
|
||||
key.dsize = strlen(keystr) + 1;
|
||||
|
||||
data = tdb_fetch(idmap_tdb, key);
|
||||
|
||||
if (data.dptr) {
|
||||
fstring scanstr;
|
||||
int the_id;
|
||||
|
||||
/* Parse and return existing uid */
|
||||
|
||||
fstrcpy(scanstr, isgroup ? "GID" : "UID");
|
||||
fstrcat(scanstr, " %d");
|
||||
|
||||
if (sscanf(data.dptr, scanstr, &the_id) == 1) {
|
||||
|
||||
/* Store uid */
|
||||
|
||||
if (id) {
|
||||
*id = the_id;
|
||||
}
|
||||
|
||||
result = True;
|
||||
}
|
||||
|
||||
free(data.dptr);
|
||||
|
||||
} else {
|
||||
|
||||
/* Allocate a new id for this rid */
|
||||
|
||||
if (id && allocate_id(id, isgroup)) {
|
||||
fstring keystr2;
|
||||
|
||||
/* Store new id */
|
||||
|
||||
slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" :
|
||||
"UID", *id);
|
||||
|
||||
data.dptr = keystr2;
|
||||
data.dsize = strlen(keystr2) + 1;
|
||||
|
||||
tdb_store(idmap_tdb, key, data, TDB_REPLACE);
|
||||
tdb_store(idmap_tdb, data, key, TDB_REPLACE);
|
||||
|
||||
result = True;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Get a uid from a user rid */
|
||||
|
||||
BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid,
|
||||
uid_t *uid)
|
||||
{
|
||||
return get_id_from_rid(domain_name, user_rid, uid, False);
|
||||
}
|
||||
|
||||
/* Get a gid from a group rid */
|
||||
|
||||
BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid,
|
||||
gid_t *gid)
|
||||
{
|
||||
return get_id_from_rid(domain_name, group_rid, gid, True);
|
||||
}
|
||||
|
||||
BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
|
||||
BOOL isgroup)
|
||||
{
|
||||
TDB_DATA key, data;
|
||||
fstring keystr;
|
||||
BOOL result = False;
|
||||
|
||||
slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id);
|
||||
|
||||
key.dptr = keystr;
|
||||
key.dsize = strlen(keystr) + 1;
|
||||
|
||||
data = tdb_fetch(idmap_tdb, key);
|
||||
|
||||
if (data.dptr) {
|
||||
char *p = data.dptr;
|
||||
fstring domain_name;
|
||||
uint32 the_rid;
|
||||
|
||||
if (next_token(&p, domain_name, "/", sizeof(fstring))) {
|
||||
|
||||
the_rid = atoi(p);
|
||||
|
||||
if (rid) {
|
||||
*rid = the_rid;
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
*domain = find_domain_from_name(domain_name);
|
||||
}
|
||||
|
||||
result = True;
|
||||
}
|
||||
|
||||
free(data.dptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Get a user rid from a uid */
|
||||
|
||||
BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
|
||||
struct winbindd_domain **domain)
|
||||
{
|
||||
return get_rid_from_id((int)uid, user_rid, domain, False);
|
||||
}
|
||||
|
||||
/* Get a group rid from a gid */
|
||||
|
||||
BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
|
||||
struct winbindd_domain **domain)
|
||||
{
|
||||
return get_rid_from_id((int)gid, group_rid, domain, True);
|
||||
}
|
||||
|
||||
/* Initialise idmap database */
|
||||
|
||||
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))) {
|
||||
DEBUG(0, ("Unable to open idmap database\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Create high water marks for group and user id */
|
||||
|
||||
if (tdb_get_int(idmap_tdb, HWM_USER) == -1) {
|
||||
if (tdb_store_int(idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
|
||||
DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdb_get_int(idmap_tdb, HWM_GROUP) == -1) {
|
||||
if (tdb_store_int(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
|
||||
DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
118
source/nsswitch/winbindd_nss.h
Normal file
118
source/nsswitch/winbindd_nss.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _WINBINDD_NTDOM_H
|
||||
#define _WINBINDD_NTDOM_H
|
||||
|
||||
#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */
|
||||
#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */
|
||||
#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variable */
|
||||
|
||||
/* Socket commands */
|
||||
|
||||
enum winbindd_cmd {
|
||||
WINBINDD_GETPWNAM_FROM_USER, /* getpwnam stuff */
|
||||
WINBINDD_GETPWNAM_FROM_UID,
|
||||
WINBINDD_GETGRNAM_FROM_GROUP, /* getgrnam stuff */
|
||||
WINBINDD_GETGRNAM_FROM_GID,
|
||||
WINBINDD_SETPWENT, /* get/set/endpwent */
|
||||
WINBINDD_ENDPWENT,
|
||||
WINBINDD_GETPWENT,
|
||||
WINBINDD_SETGRENT, /* get/set/endgrent */
|
||||
WINBINDD_ENDGRENT,
|
||||
WINBINDD_GETGRENT,
|
||||
WINBINDD_PAM_AUTH
|
||||
};
|
||||
|
||||
/* Winbind request structure */
|
||||
|
||||
struct winbindd_request {
|
||||
enum winbindd_cmd cmd; /* Winbindd command to execute */
|
||||
pid_t pid; /* pid of calling process */
|
||||
|
||||
union {
|
||||
fstring username; /* getpwnam() */
|
||||
fstring groupname; /* getgrnam() */
|
||||
uid_t uid; /* getpwuid() */
|
||||
gid_t gid; /* getgrgid() */
|
||||
struct {
|
||||
/* the following is used by pam_winbind */
|
||||
fstring user;
|
||||
fstring pass;
|
||||
} auth;
|
||||
} data;
|
||||
fstring domain; /* {set,get,end}{pw,gr}ent() */
|
||||
};
|
||||
|
||||
/* Response values */
|
||||
|
||||
enum winbindd_result {
|
||||
WINBINDD_ERROR,
|
||||
WINBINDD_OK
|
||||
};
|
||||
|
||||
/* Winbind response structure */
|
||||
|
||||
struct winbindd_response {
|
||||
|
||||
/* Header information */
|
||||
|
||||
int length; /* Length of response */
|
||||
enum winbindd_result result; /* Result code */
|
||||
|
||||
/* Fixed length return data */
|
||||
|
||||
union {
|
||||
|
||||
/* getpwnam, getpwuid, getpwent */
|
||||
|
||||
struct winbindd_pw {
|
||||
fstring pw_name;
|
||||
fstring pw_passwd;
|
||||
uid_t pw_uid;
|
||||
gid_t pw_gid;
|
||||
fstring pw_gecos;
|
||||
fstring pw_dir;
|
||||
fstring pw_shell;
|
||||
int pwent_ndx;
|
||||
} pw;
|
||||
|
||||
/* getgrnam, getgrgid, getgrent */
|
||||
|
||||
struct winbindd_gr {
|
||||
fstring gr_name;
|
||||
fstring gr_passwd;
|
||||
gid_t gr_gid;
|
||||
int num_gr_mem;
|
||||
int grent_ndx;
|
||||
} gr;
|
||||
|
||||
} data;
|
||||
|
||||
/* Variable length return data */
|
||||
|
||||
void *extra_data; /* getgrnam, getgrgid, getgrent */
|
||||
};
|
||||
|
||||
#endif
|
97
source/nsswitch/winbindd_pam.c
Normal file
97
source/nsswitch/winbindd_pam.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
|
||||
Winbind daemon - pam auuth funcions
|
||||
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
/************************************************************************
|
||||
form a key for fetching a domain trust password
|
||||
************************************************************************/
|
||||
static char *trust_keystr(char *domain)
|
||||
{
|
||||
static fstring keystr;
|
||||
slprintf(keystr,sizeof(keystr),"%s/%s", SECRETS_MACHINE_ACCT_PASS, domain);
|
||||
return keystr;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Routine to get the trust account password for a domain.
|
||||
The user of this function must have locked the trust password file.
|
||||
************************************************************************/
|
||||
static BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd, time_t *pass_last_set_time)
|
||||
{
|
||||
struct machine_acct_pass *pass;
|
||||
size_t size;
|
||||
|
||||
if (!(pass = secrets_fetch(trust_keystr(domain), &size)) ||
|
||||
size != sizeof(*pass)) return False;
|
||||
|
||||
if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
|
||||
memcpy(ret_pwd, pass->hash, 16);
|
||||
free(pass);
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/* Return a password structure from a username. Specify whether cached data
|
||||
can be returned. */
|
||||
|
||||
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
|
||||
{
|
||||
NET_USER_INFO_3 info3;
|
||||
uchar ntpw[16];
|
||||
uchar lmpw[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",
|
||||
state->request.data.auth.user));
|
||||
|
||||
/* Parse domain and username */
|
||||
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 (!_get_trust_account_password(name_domain, trust_passwd, NULL)) return WINBINDD_ERROR;
|
||||
|
||||
nt_lm_owf_gen(state->request.data.auth.pass, ntpw, lmpw);
|
||||
|
||||
slprintf(server, sizeof(server), "\\\\%s", server_state.controller);
|
||||
|
||||
status = domain_client_validate_backend(server,
|
||||
name_user, name_domain,
|
||||
global_myname, SEC_CHAN_WKSTA,
|
||||
trust_passwd,
|
||||
NULL,
|
||||
lmpw, sizeof(lmpw),
|
||||
ntpw, sizeof(ntpw), &info3);
|
||||
|
||||
if (status != NT_STATUS_NOPROBLEMO) return WINBINDD_ERROR;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
113
source/nsswitch/winbindd_proto.h
Normal file
113
source/nsswitch/winbindd_proto.h
Normal file
@ -0,0 +1,113 @@
|
||||
#ifndef _WINBINDD_PROTO_H_
|
||||
#define _WINBINDD_PROTO_H_
|
||||
/* This file is automatically generated with "make proto". DO NOT EDIT */
|
||||
|
||||
|
||||
/*The following definitions come from nsswitch/winbindd.c */
|
||||
|
||||
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,
|
||||
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,
|
||||
struct winbindd_pw *pw);
|
||||
void winbindd_fill_uid_cache_entry(char *domain, uid_t uid,
|
||||
struct winbindd_pw *pw);
|
||||
void winbindd_fill_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,
|
||||
struct winbindd_gr *gr, void *extra_data,
|
||||
int extra_data_len);
|
||||
BOOL winbindd_fetch_user_cache(char *domain_name,
|
||||
struct acct_info **sam_entries,
|
||||
int *num_entries);
|
||||
BOOL winbindd_fetch_group_cache(char *domain_name,
|
||||
struct acct_info **sam_entries,
|
||||
int *num_entries);
|
||||
BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
|
||||
struct winbindd_pw *pw);
|
||||
BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
|
||||
struct winbindd_pw *pw);
|
||||
BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
|
||||
struct winbindd_gr *gr,
|
||||
void **extra_data, int *extra_data_len);
|
||||
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);
|
||||
|
||||
/*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_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);
|
||||
|
||||
/*The following definitions come from nsswitch/winbindd_idmap.c */
|
||||
|
||||
BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid,
|
||||
uid_t *uid);
|
||||
BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid,
|
||||
gid_t *gid);
|
||||
BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
|
||||
BOOL isgroup);
|
||||
BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
|
||||
struct winbindd_domain **domain);
|
||||
BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
|
||||
struct winbindd_domain **domain);
|
||||
BOOL winbindd_idmap_init(void);
|
||||
|
||||
/*The following definitions come from nsswitch/winbindd_pam.c */
|
||||
|
||||
enum winbindd_result winbindd_pam_auth(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_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);
|
||||
|
||||
/*The following definitions come from nsswitch/winbindd_util.c */
|
||||
|
||||
BOOL domain_handles_open(struct winbindd_domain *domain);
|
||||
void establish_connections(void) ;
|
||||
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,
|
||||
enum SID_NAME_USE *type);
|
||||
BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
|
||||
DOM_SID *sid, char *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_groupinfo(struct winbindd_domain *domain,
|
||||
uint32 group_rid, GROUP_INFO_CTR *info);
|
||||
BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
|
||||
uint32 group_rid, uint32 *num_names,
|
||||
uint32 **rid_mem, char ***names,
|
||||
enum SID_NAME_USE **name_types);
|
||||
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);
|
||||
struct winbindd_domain *find_domain_from_name(char *domain_name);
|
||||
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);
|
||||
#endif /* _WINBINDD_PROTO_H_ */
|
412
source/nsswitch/winbindd_user.c
Normal file
412
source/nsswitch/winbindd_user.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon - user related function
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
|
||||
/* 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)
|
||||
{
|
||||
pstring homedir;
|
||||
fstring name_domain, name_user;
|
||||
|
||||
if (!pw || !name) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fill in uid/gid */
|
||||
|
||||
pw->pw_uid = unix_uid;
|
||||
pw->pw_gid = unix_gid;
|
||||
|
||||
/* Username */
|
||||
|
||||
safe_strcpy(pw->pw_name, name, sizeof(pw->pw_name) - 1);
|
||||
|
||||
/* Full name (gecos) */
|
||||
|
||||
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. */
|
||||
|
||||
parse_domain_user(name, name_domain, name_user);
|
||||
|
||||
pstrcpy(homedir, lp_template_homedir());
|
||||
|
||||
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);
|
||||
|
||||
/* 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 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)
|
||||
{
|
||||
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;
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (strequal(name_domain, "")) {
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Check for cached user entry */
|
||||
|
||||
if (winbindd_fetch_user_cache_entry(name_domain, name_user,
|
||||
&state->response.data.pw)) {
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
slprintf(name,sizeof(name),"%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)) {
|
||||
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));
|
||||
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
|
||||
winbind_lookup_userinfo() */
|
||||
|
||||
sid_split_rid(&user_sid, &user_rid);
|
||||
|
||||
/* 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));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
group_rid = user_info.info.id21->group_rid;
|
||||
unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
|
||||
sizeof(gecos_name) - 1);
|
||||
|
||||
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);
|
||||
|
||||
winbindd_fill_user_cache_entry(name_domain, name_user,
|
||||
&state->response.data.pw);
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Return a password structure given a uid number */
|
||||
|
||||
enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state
|
||||
*state)
|
||||
{
|
||||
DOM_SID user_sid;
|
||||
struct winbindd_domain *domain;
|
||||
uint32 user_rid, group_rid;
|
||||
fstring user_name, gecos_name;
|
||||
enum SID_NAME_USE name_type;
|
||||
SAM_USERINFO_CTR user_info;
|
||||
gid_t gid;
|
||||
|
||||
/* Get rid from uid */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Check for cached uid entry */
|
||||
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)) {
|
||||
fstring temp;
|
||||
|
||||
sid_to_string(temp, &user_sid);
|
||||
DEBUG(1, ("Could not lookup sid %s\n", temp));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
string_sub(user_name, "\\", "/", 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));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
group_rid = user_info.info.id21->group_rid;
|
||||
unistr2_to_ascii(gecos_name, &user_info.info.id21->uni_full_name,
|
||||
sizeof(gecos_name) - 1);
|
||||
|
||||
free_samr_userinfo_ctr(&user_info);
|
||||
|
||||
/* Resolve gid number */
|
||||
|
||||
if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
|
||||
DEBUG(1, ("error getting group id for user %s\n", user_name));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
/* Fill in password structure */
|
||||
|
||||
winbindd_fill_pwent(&state->response.data.pw, user_name,
|
||||
state->request.data.uid, gid, gecos_name);
|
||||
|
||||
winbindd_fill_uid_cache_entry(domain->name, state->request.data.uid,
|
||||
&state->response.data.pw);
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* set/get/endpwent functions
|
||||
*/
|
||||
|
||||
/* Rewind file pointer for ntdom passwd database */
|
||||
|
||||
enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
|
||||
{
|
||||
struct winbindd_domain *tmp;
|
||||
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
/* Free old static data if it exists */
|
||||
|
||||
if (state->getpwent_state != NULL) {
|
||||
free_getent_state(state->getpwent_state);
|
||||
state->getpwent_state = NULL;
|
||||
}
|
||||
|
||||
/* Create sam pipes for each domain we know about */
|
||||
|
||||
for(tmp = domain_list; tmp != NULL; tmp = tmp->next) {
|
||||
struct getent_state *domain_state;
|
||||
|
||||
/* Skip domains other than WINBINDD_DOMAIN environment variable */
|
||||
|
||||
if ((strcmp(state->request.domain, "") != 0) &&
|
||||
(strcmp(state->request.domain, tmp->name) != 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create a state record for this domain */
|
||||
|
||||
if ((domain_state = (struct getent_state *)
|
||||
malloc(sizeof(struct getent_state))) == NULL) {
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(domain_state);
|
||||
domain_state->domain = tmp;
|
||||
|
||||
/* Add to list of open domains */
|
||||
|
||||
DLIST_ADD(state->getpwent_state, domain_state)
|
||||
}
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Close file pointer to ntdom passwd database */
|
||||
|
||||
enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
|
||||
{
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
free_getent_state(state->getpwent_state);
|
||||
state->getpwent_state = NULL;
|
||||
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/* Fetch next passwd entry from ntdom database */
|
||||
|
||||
enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
|
||||
{
|
||||
if (state == NULL) return WINBINDD_ERROR;
|
||||
|
||||
/* Process the current head of the getent_state list */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ent->got_sam_entries = True;
|
||||
}
|
||||
|
||||
/* Send back a user */
|
||||
|
||||
while (ent->sam_entry_index < ent->num_sam_entries) {
|
||||
enum winbindd_result result;
|
||||
fstring domain_user_name;
|
||||
char *user_name = (ent->sam_entries)
|
||||
[ent->sam_entry_index].acct_name;
|
||||
|
||||
/* Don't bother with machine accounts */
|
||||
|
||||
if (user_name[strlen(user_name) - 1] == '$') {
|
||||
ent->sam_entry_index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Prepend domain to name */
|
||||
|
||||
slprintf(domain_user_name, sizeof(domain_user_name),
|
||||
"%s/%s", ent->domain->name, user_name);
|
||||
|
||||
/* Get passwd entry from user name */
|
||||
|
||||
fstrcpy(state->request.data.username, domain_user_name);
|
||||
result = winbindd_getpwnam_from_user(state);
|
||||
|
||||
ent->sam_entry_index++;
|
||||
|
||||
/* Return if user lookup worked */
|
||||
|
||||
if (result == WINBINDD_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Try next user */
|
||||
|
||||
DEBUG(1, ("could not getpwnam_from_user for username %s\n",
|
||||
domain_user_name));
|
||||
}
|
||||
|
||||
/* We've exhausted all users for this pipe - close it down and
|
||||
start on the next one. */
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Free mallocated memory for sam entries. The data stored here
|
||||
may have been allocated from the cache. */
|
||||
|
||||
if (ent->sam_entries != NULL) free(ent->sam_entries);
|
||||
ent->sam_entries = NULL;
|
||||
|
||||
/* Free state information for this domain */
|
||||
|
||||
{
|
||||
struct getent_state *old_ent;
|
||||
|
||||
old_ent = state->getpwent_state;
|
||||
DLIST_REMOVE(state->getpwent_state, state->getpwent_state);
|
||||
free(old_ent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Out of pipes so we're done */
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
633
source/nsswitch/winbindd_util.c
Normal file
633
source/nsswitch/winbindd_util.c
Normal file
@ -0,0 +1,633 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Winbind daemon for ntdom nss module
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "winbindd.h"
|
||||
#include "sids.h"
|
||||
|
||||
BOOL domain_handles_open(struct winbindd_domain *domain)
|
||||
{
|
||||
return 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 &&
|
||||
strcmp(lp_passwordserver(),"*") != 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static struct winbindd_domain *add_trusted_domain(char *domain_name)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
DEBUG(1, ("adding trusted domain %s\n", domain_name));
|
||||
|
||||
/* Create new domain entry */
|
||||
|
||||
if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fill in fields */
|
||||
|
||||
ZERO_STRUCTP(domain);
|
||||
|
||||
if (domain_name) {
|
||||
fstrcpy(domain->name, domain_name);
|
||||
}
|
||||
|
||||
/* Link to domain list */
|
||||
|
||||
DLIST_ADD(domain_list, domain);
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
BOOL result;
|
||||
int i;
|
||||
|
||||
DEBUG(1, ("getting trusted domain list\n"));
|
||||
|
||||
/* Add our workgroup - keep handle to look up trusted domains */
|
||||
if (!add_trusted_domain(lp_workgroup())) {
|
||||
DEBUG(0, ("could not add record for domain %s\n", lp_workgroup()));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Enumerate list of trusted domains */
|
||||
result = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx,
|
||||
&num_doms, &domains, &sids);
|
||||
|
||||
if (!result || !domains) return False;
|
||||
|
||||
/* Add each domain to the trusted domain list */
|
||||
for(i = 0; i < num_doms; i++) {
|
||||
if (!add_trusted_domain(domains[i])) {
|
||||
DEBUG(0, ("could not add record for domain %s\n", domains[i]));
|
||||
result = False;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
free_char_array(num_doms, domains);
|
||||
free_sid_array(num_doms, sids);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/* 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 */
|
||||
if (!domain->got_domain_info) {
|
||||
domain->got_domain_info = get_domain_info(domain);
|
||||
if (!domain->got_domain_info) return False;
|
||||
}
|
||||
|
||||
/* Open sam handle if it isn't already open */
|
||||
if (!domain->sam_handle_open) {
|
||||
domain->sam_handle_open =
|
||||
samr_connect(domain->controller, SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
&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) {
|
||||
domain->sam_dom_handle_open =
|
||||
samr_open_domain(&domain->sam_handle,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED, &domain->sid,
|
||||
&domain->sam_dom_handle);
|
||||
if (!domain->sam_dom_handle_open) return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static void winbindd_kill_connections(void)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
|
||||
DEBUG(1,("killing winbindd connections\n"));
|
||||
|
||||
server_state.pwdb_initialised = False;
|
||||
server_state.lsa_handle_open = False;
|
||||
lsa_close(&server_state.lsa_handle);
|
||||
|
||||
for (domain=domain_list; domain; domain=domain->next) {
|
||||
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;
|
||||
}
|
||||
DLIST_REMOVE(domain_list, domain);
|
||||
free(domain);
|
||||
}
|
||||
}
|
||||
|
||||
void establish_connections(void)
|
||||
{
|
||||
struct winbindd_domain *domain;
|
||||
static time_t lastt;
|
||||
time_t t;
|
||||
|
||||
t = time(NULL);
|
||||
if (t - lastt < WINBINDD_ESTABLISH_LOOP) return;
|
||||
lastt = t;
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
if (!server_state.pwdb_initialised) {
|
||||
fstrcpy(server_state.controller, lp_passwordserver());
|
||||
if (strcmp(server_state.controller,"*") == 0) {
|
||||
if (!resolve_dc_name(lp_workgroup(), server_state.controller)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
server_state.pwdb_initialised = pwdb_initialise(False);
|
||||
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);
|
||||
if (!server_state.lsa_handle_open) return;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
BOOL res;
|
||||
uint32 enum_ctx = 0;
|
||||
uint32 num_doms = 0;
|
||||
char **domains = NULL;
|
||||
DOM_SID **sids = NULL;
|
||||
|
||||
if (domain == NULL) {
|
||||
return False;
|
||||
}
|
||||
|
||||
DEBUG(1, ("looking up sid for domain %s\n", domain_name));
|
||||
|
||||
/* Get controller name for domain */
|
||||
if (!resolve_dc_name(domain_name, domain->controller)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (strequal(domain->controller, server_state.controller)) {
|
||||
/* Do a level 5 query info policy */
|
||||
return lsa_query_info_pol(&server_state.lsa_handle, 0x05,
|
||||
level5_dom, &domain->sid);
|
||||
}
|
||||
|
||||
/* Use lsaenumdomains to get sid for this domain */
|
||||
|
||||
res = lsa_enum_trust_dom(&server_state.lsa_handle, &enum_ctx,
|
||||
&num_doms, &domains, &sids);
|
||||
|
||||
/* Look for domain name */
|
||||
|
||||
if (res && domains && sids) {
|
||||
int found = False;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < num_doms; i++) {
|
||||
if (strequal(domain_name, domains[i])) {
|
||||
sid_copy(&domain->sid, sids[i]);
|
||||
found = True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fstring sid_str;
|
||||
|
||||
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));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Lookup OK */
|
||||
|
||||
domain->got_domain_info = 1;
|
||||
|
||||
sid_to_string(sid_str, &domain->sid);
|
||||
DEBUG(1, ("found sid %s for domain %s\n", sid_str, domain->name));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Lookup a sid in a domain from a name */
|
||||
|
||||
BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
|
||||
char *name, DOM_SID *sid,
|
||||
enum SID_NAME_USE *type)
|
||||
{
|
||||
int num_sids = 0, num_names = 1;
|
||||
DOM_SID *sids = NULL;
|
||||
uint32 *types = NULL;
|
||||
BOOL res;
|
||||
|
||||
/* Don't bother with machine accounts */
|
||||
|
||||
if (name[strlen(name) - 1] == '$') {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Lookup name */
|
||||
|
||||
res = lsa_lookup_names(&server_state.lsa_handle, num_names, (char **)&name,
|
||||
&sids, &types, &num_sids);
|
||||
|
||||
/* Return rid and type if lookup successful */
|
||||
|
||||
if (res) {
|
||||
|
||||
/* Return sid */
|
||||
|
||||
if ((sid != NULL) && (sids != NULL)) {
|
||||
sid_copy(sid, &sids[0]);
|
||||
}
|
||||
|
||||
/* Return name type */
|
||||
|
||||
if ((type != NULL) && (types != NULL)) {
|
||||
*type = types[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
|
||||
if (types != NULL) free(types);
|
||||
if (sids != NULL) free(sids);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Lookup a name in a domain from a sid */
|
||||
|
||||
BOOL winbindd_lookup_name_by_sid(struct winbindd_domain *domain,
|
||||
DOM_SID *sid, char *name,
|
||||
enum SID_NAME_USE *type)
|
||||
{
|
||||
int num_sids = 1, num_names = 0;
|
||||
uint32 *types = NULL;
|
||||
char **names;
|
||||
BOOL res;
|
||||
|
||||
/* Lookup name */
|
||||
res = lsa_lookup_sids(&server_state.lsa_handle, num_sids, &sid, &names,
|
||||
&types, &num_names);
|
||||
|
||||
/* Return name and type if successful */
|
||||
|
||||
if (res) {
|
||||
|
||||
/* Return name */
|
||||
|
||||
if ((names != NULL) && (name != NULL)) {
|
||||
fstrcpy(name, names[0]);
|
||||
}
|
||||
|
||||
/* Return name type */
|
||||
|
||||
if ((type != NULL) && (types != NULL)) {
|
||||
*type = types[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
|
||||
safe_free(types);
|
||||
free_char_array(num_names, names);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Lookup user information from a rid */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Lookup group information from a rid */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Lookup group membership given a rid */
|
||||
|
||||
BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain,
|
||||
uint32 group_rid, uint32 *num_names,
|
||||
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);
|
||||
}
|
||||
|
||||
/* Globals for domain list stuff */
|
||||
|
||||
struct winbindd_domain *domain_list = NULL;
|
||||
|
||||
/* Given a domain name, return the struct winbindd domain info for it */
|
||||
|
||||
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) return NULL;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free state information held for {set,get,end}{pw,gr}ent() functions */
|
||||
|
||||
void free_getent_state(struct getent_state *state)
|
||||
{
|
||||
struct getent_state *temp;
|
||||
|
||||
/* Iterate over state list */
|
||||
|
||||
temp = state;
|
||||
|
||||
while(temp != NULL) {
|
||||
struct getent_state *next;
|
||||
|
||||
/* Free sam entries then list entry */
|
||||
|
||||
safe_free(state->sam_entries);
|
||||
DLIST_REMOVE(state, state);
|
||||
next = temp->next;
|
||||
|
||||
free(temp);
|
||||
temp = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse list of arguments to winbind uid or winbind gid parameters */
|
||||
|
||||
static BOOL parse_id_list(char *paramstr, BOOL is_user)
|
||||
{
|
||||
uid_t id_low, id_high = 0;
|
||||
|
||||
/* Parse entry */
|
||||
|
||||
if (sscanf(paramstr, "%u-%u", &id_low, &id_high) != 2) {
|
||||
DEBUG(0, ("winbid %s parameter invalid\n",
|
||||
is_user ? "uid" : "gid"));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Store id info */
|
||||
|
||||
if (is_user) {
|
||||
server_state.uid_low = id_low;
|
||||
server_state.uid_high = id_high;
|
||||
} else {
|
||||
server_state.gid_low = id_low;
|
||||
server_state.gid_high = id_high;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Initialise trusted domain info */
|
||||
|
||||
BOOL winbindd_param_init(void)
|
||||
{
|
||||
/* Parse winbind uid and winbind_gid parameters */
|
||||
|
||||
if (!(parse_id_list(lp_winbind_uid(), True) &&
|
||||
parse_id_list(lp_winbind_gid(), False))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Check for reversed uid and gid ranges */
|
||||
|
||||
if (server_state.uid_low > server_state.uid_high) {
|
||||
DEBUG(0, ("uid range invalid\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (server_state.gid_low > server_state.gid_high) {
|
||||
DEBUG(0, ("gid range for invalid\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Convert a enum winbindd_cmd to a string */
|
||||
|
||||
char *winbindd_cmd_to_string(enum winbindd_cmd cmd)
|
||||
{
|
||||
char *result;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case WINBINDD_GETPWNAM_FROM_USER:
|
||||
result = "getpwnam from user";
|
||||
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:
|
||||
result = "invalid command";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/* 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;
|
||||
p = strchr(domuser,'/');
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user