2 Unix SMB/CIFS implementation.
4 winbind client common code
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Tridgell 2000
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this library; if not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
25 #include "winbind_nss_config.h"
26 #include "winbindd_nss.h"
28 /* Global variables. These are effectively the client state information */
30 int winbindd_fd
= -1; /* fd for winbindd socket */
31 static char *excluded_domain
;
33 /* Free a response structure */
35 void free_response(struct winbindd_response
*response
)
37 /* Free any allocated extra_data */
40 SAFE_FREE(response
->extra_data
);
44 smbd needs to be able to exclude lookups for its own domain
46 void winbind_exclude_domain(const char *domain
)
48 SAFE_FREE(excluded_domain
);
49 excluded_domain
= strdup(domain
);
53 /* Initialise a request structure */
55 void init_request(struct winbindd_request
*request
, int request_type
)
57 static char *domain_env
;
58 static BOOL initialised
;
60 request
->length
= sizeof(struct winbindd_request
);
62 request
->cmd
= (enum winbindd_cmd
)request_type
;
63 request
->pid
= getpid();
64 request
->domain
[0] = '\0';
68 domain_env
= getenv(WINBINDD_DOMAIN_ENV
);
72 strncpy(request
->domain
, domain_env
,
73 sizeof(request
->domain
) - 1);
74 request
->domain
[sizeof(request
->domain
) - 1] = '\0';
78 /* Initialise a response structure */
80 void init_response(struct winbindd_response
*response
)
82 /* Initialise return value */
84 response
->result
= WINBINDD_ERROR
;
87 /* Close established socket */
91 if (winbindd_fd
!= -1) {
97 /* Connect to winbindd socket */
99 int winbind_open_pipe_sock(void)
101 struct sockaddr_un sunaddr
;
102 static pid_t our_pid
;
106 if (our_pid
!= getpid()) {
111 if (winbindd_fd
!= -1) {
115 /* Check permissions on unix socket directory */
117 if (lstat(WINBINDD_SOCKET_DIR
, &st
) == -1) {
121 if (!S_ISDIR(st
.st_mode
) ||
122 (st
.st_uid
!= 0 && st
.st_uid
!= geteuid())) {
126 /* Connect to socket */
128 strncpy(path
, WINBINDD_SOCKET_DIR
, sizeof(path
) - 1);
129 path
[sizeof(path
) - 1] = '\0';
131 strncat(path
, "/", sizeof(path
) - 1);
132 path
[sizeof(path
) - 1] = '\0';
134 strncat(path
, WINBINDD_SOCKET_NAME
, sizeof(path
) - 1);
135 path
[sizeof(path
) - 1] = '\0';
137 ZERO_STRUCT(sunaddr
);
138 sunaddr
.sun_family
= AF_UNIX
;
139 strncpy(sunaddr
.sun_path
, path
, sizeof(sunaddr
.sun_path
) - 1);
141 /* If socket file doesn't exist, don't bother trying to connect
142 with retry. This is an attempt to make the system usable when
143 the winbindd daemon is not running. */
145 if (lstat(path
, &st
) == -1) {
149 /* Check permissions on unix socket file */
151 if (!S_ISSOCK(st
.st_mode
) ||
152 (st
.st_uid
!= 0 && st
.st_uid
!= geteuid())) {
156 /* Connect to socket */
158 if ((winbindd_fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1) {
162 if (connect(winbindd_fd
, (struct sockaddr
*)&sunaddr
,
163 sizeof(sunaddr
)) == -1) {
171 /* Write data to winbindd socket */
173 int write_sock(void *buffer
, int count
)
175 int result
, nwritten
;
177 /* Open connection to winbind daemon */
181 if (winbind_open_pipe_sock() == -1) {
185 /* Write data to socket */
189 while(nwritten
< count
) {
193 /* Catch pipe close on other end by checking if a read()
194 call would not block by calling select(). */
197 FD_SET(winbindd_fd
, &r_fds
);
200 if (select(winbindd_fd
+ 1, &r_fds
, NULL
, NULL
, &tv
) == -1) {
202 return -1; /* Select error */
205 /* Write should be OK if fd not available for reading */
207 if (!FD_ISSET(winbindd_fd
, &r_fds
)) {
211 result
= write(winbindd_fd
,
212 (char *)buffer
+ nwritten
,
215 if ((result
== -1) || (result
== 0)) {
227 /* Pipe has closed on remote end */
237 /* Read data from winbindd socket */
239 static int read_sock(void *buffer
, int count
)
241 int result
= 0, nread
= 0;
243 /* Read data from socket */
245 while(nread
< count
) {
247 result
= read(winbindd_fd
, (char *)buffer
+ nread
,
250 if ((result
== -1) || (result
== 0)) {
252 /* Read failed. I think the only useful thing we
253 can do here is just return -1 and fail since the
254 transaction has failed half way through. */
268 int read_reply(struct winbindd_response
*response
)
270 int result1
, result2
= 0;
276 /* Read fixed length response */
278 if ((result1
= read_sock(response
, sizeof(struct winbindd_response
)))
284 /* We actually send the pointer value of the extra_data field from
285 the server. This has no meaning in the client's address space
286 so we clear it out. */
288 response
->extra_data
= NULL
;
290 /* Read variable length response */
292 if (response
->length
> sizeof(struct winbindd_response
)) {
293 int extra_data_len
= response
->length
-
294 sizeof(struct winbindd_response
);
296 /* Mallocate memory for extra data */
298 if (!(response
->extra_data
= malloc(extra_data_len
))) {
302 if ((result2
= read_sock(response
->extra_data
, extra_data_len
))
304 free_response(response
);
309 /* Return total amount of data read */
311 return result1
+ result2
;
315 * send simple types of requests
318 NSS_STATUS
winbindd_send_request(int req_type
, struct winbindd_request
*request
)
320 struct winbindd_request lrequest
;
322 /* Check for our tricky environment variable */
324 if (getenv(WINBINDD_DONT_ENV
)) {
325 return NSS_STATUS_NOTFOUND
;
328 /* smbd may have excluded this domain */
329 if (excluded_domain
&&
330 strcasecmp(excluded_domain
, request
->domain
) == 0) {
331 return NSS_STATUS_NOTFOUND
;
335 ZERO_STRUCT(lrequest
);
339 /* Fill in request and send down pipe */
341 init_request(request
, req_type
);
343 if (write_sock(request
, sizeof(*request
)) == -1) {
344 return NSS_STATUS_UNAVAIL
;
347 return NSS_STATUS_SUCCESS
;
351 * Get results from winbindd request
354 NSS_STATUS
winbindd_get_response(struct winbindd_response
*response
)
356 struct winbindd_response lresponse
;
359 ZERO_STRUCT(lresponse
);
360 response
= &lresponse
;
363 init_response(response
);
366 if (read_reply(response
) == -1) {
367 return NSS_STATUS_UNAVAIL
;
370 /* Throw away extra data if client didn't request it */
371 if (response
== &lresponse
) {
372 free_response(response
);
375 /* Copy reply data from socket */
376 if (response
->result
!= WINBINDD_OK
) {
377 return NSS_STATUS_NOTFOUND
;
380 return NSS_STATUS_SUCCESS
;
383 /* Handle simple types of requests */
385 NSS_STATUS
winbindd_request(int req_type
,
386 struct winbindd_request
*request
,
387 struct winbindd_response
*response
)
391 status
= winbindd_send_request(req_type
, request
);
392 if (status
!= NSS_STATUS_SUCCESS
)
394 return winbindd_get_response(response
);