2 Unix SMB/Netbios implementation.
5 winbind client common code
7 Copyright (C) Tim Potter 2000
8 Copyright (C) Andrew Tridgell 2000
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this library; if not, write to the
22 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.
26 #include "winbind_nss_config.h"
27 #include "winbindd_nss.h"
29 /* Global variables. These are effectively the client state information */
31 static int established_socket
= -1; /* fd for winbindd socket */
33 /* Initialise a request structure */
35 void init_request(struct winbindd_request
*request
, int request_type
)
37 static char *domain_env
;
38 static BOOL initialised
;
40 request
->cmd
= request_type
;
41 request
->pid
= getpid();
42 request
->domain
[0] = '\0';
46 domain_env
= getenv(WINBINDD_DOMAIN_ENV
);
50 strncpy(request
->domain
, domain_env
,
51 sizeof(request
->domain
) - 1);
52 request
->domain
[sizeof(request
->domain
) - 1] = '\0';
56 /* Initialise a response structure */
58 void init_response(struct winbindd_response
*response
)
60 /* Initialise return value */
62 response
->result
= NSS_STATUS_UNAVAIL
;
65 /* Close established socket */
69 if (established_socket
!= -1) {
70 close(established_socket
);
71 established_socket
= -1;
75 /* Connect to winbindd socket */
77 static int open_pipe_sock(void)
79 struct sockaddr_un sunaddr
;
84 if (our_pid
!= getpid()) {
85 if (established_socket
!= -1) {
86 close(established_socket
);
88 established_socket
= -1;
92 if (established_socket
!= -1) {
93 return established_socket
;
96 /* Check permissions on unix socket directory */
98 if (lstat(WINBINDD_SOCKET_DIR
, &st
) == -1) {
102 if (!S_ISDIR(st
.st_mode
) || (st
.st_uid
!= 0)) {
106 /* Connect to socket */
108 strncpy(path
, WINBINDD_SOCKET_DIR
, sizeof(path
) - 1);
109 path
[sizeof(path
) - 1] = '\0';
111 strncat(path
, "/", sizeof(path
) - 1);
112 path
[sizeof(path
) - 1] = '\0';
114 strncat(path
, WINBINDD_SOCKET_NAME
, sizeof(path
) - 1);
115 path
[sizeof(path
) - 1] = '\0';
117 ZERO_STRUCT(sunaddr
);
118 sunaddr
.sun_family
= AF_UNIX
;
119 strncpy(sunaddr
.sun_path
, path
, sizeof(sunaddr
.sun_path
) - 1);
121 /* If socket file doesn't exist, don't bother trying to connect
122 with retry. This is an attempt to make the system usable when
123 the winbindd daemon is not running. */
125 if (lstat(path
, &st
) == -1) {
129 /* Check permissions on unix socket file */
131 if (!S_ISSOCK(st
.st_mode
) || (st
.st_uid
!= 0)) {
135 /* Connect to socket */
137 if ((established_socket
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1) {
141 if (connect(established_socket
, (struct sockaddr
*)&sunaddr
,
142 sizeof(sunaddr
)) == -1) {
147 return established_socket
;
150 /* Write data to winbindd socket with timeout */
152 int write_sock(void *buffer
, int count
)
154 int result
, nwritten
;
156 /* Open connection to winbind daemon */
160 if (open_pipe_sock() == -1) {
164 /* Write data to socket */
168 while(nwritten
< count
) {
173 /* Catch pipe close on other end by checking if a read()
174 call would not block by calling select(). */
177 FD_SET(established_socket
, &r_fds
);
180 if ((selret
= select(established_socket
+ 1, &r_fds
,
181 NULL
, NULL
, &tv
)) == -1) {
183 return -1; /* Select error */
186 /* Write should be OK if fd not available for reading */
188 if (!FD_ISSET(established_socket
, &r_fds
)) {
192 result
= write(established_socket
,
193 (char *)buffer
+ nwritten
,
196 if ((result
== -1) || (result
== 0)) {
208 /* Pipe has closed on remote end */
218 /* Read data from winbindd socket with timeout */
220 static int read_sock(void *buffer
, int count
)
222 int result
= 0, nread
= 0;
224 /* Read data from socket */
226 while(nread
< count
) {
228 result
= read(established_socket
, (char *)buffer
+ nread
,
231 if ((result
== -1) || (result
== 0)) {
233 /* Read failed. I think the only useful thing we
234 can do here is just return -1 and fail since the
235 transaction has failed half way through. */
249 int read_reply(struct winbindd_response
*response
)
251 int result1
, result2
= 0;
257 /* Read fixed length response */
259 if ((result1
= read_sock(response
, sizeof(struct winbindd_response
)))
265 /* We actually send the pointer value of the extra_data field from
266 the server. This has no meaning in the client's address space
267 so we clear it out. */
269 response
->extra_data
= NULL
;
271 /* Read variable length response */
273 if (response
->length
> sizeof(struct winbindd_response
)) {
274 int extra_data_len
= response
->length
-
275 sizeof(struct winbindd_response
);
277 /* Mallocate memory for extra data */
279 if (!(response
->extra_data
= malloc(extra_data_len
))) {
283 if ((result2
= read_sock(response
->extra_data
, extra_data_len
))
289 /* Return total amount of data read */
291 return result1
+ result2
;
294 /* Free a response structure */
296 void free_response(struct winbindd_response
*response
)
298 /* Free any allocated extra_data */
300 if (response
&& response
->extra_data
) {
301 free(response
->extra_data
);
302 response
->extra_data
= NULL
;
306 /* Handle simple types of requests */
308 enum nss_status
winbindd_request(int req_type
,
309 struct winbindd_request
*request
,
310 struct winbindd_response
*response
)
312 struct winbindd_request lrequest
;
313 struct winbindd_response lresponse
;
315 /* Check for our tricky environment variable */
317 if (getenv(WINBINDD_DONT_ENV
)) {
318 return NSS_STATUS_NOTFOUND
;
322 ZERO_STRUCT(lresponse
);
323 response
= &lresponse
;
327 ZERO_STRUCT(lrequest
);
331 /* Fill in request and send down pipe */
333 init_request(request
, req_type
);
334 init_response(response
);
336 if (write_sock(request
, sizeof(*request
)) == -1) {
337 return NSS_STATUS_UNAVAIL
;
341 if (read_reply(response
) == -1) {
342 return NSS_STATUS_UNAVAIL
;
345 /* Throw away extra data if client didn't request it */
346 if (response
== &lresponse
) {
347 free_response(response
);
350 /* Copy reply data from socket */
351 if (response
->result
!= WINBINDD_OK
) {
352 return NSS_STATUS_NOTFOUND
;
355 return NSS_STATUS_SUCCESS
;