2 Unix SMB/Netbios implementation.
5 Winbind daemon for ntdom nss module
7 Copyright (C) Tim Potter 2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program 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
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* List of all connected clients */
28 static struct winbindd_cli_state
*client_list
;
30 /* Reload configuration */
32 static BOOL
reload_services_file(void)
34 pstring servicesf
= CONFIGFILE
;
38 ret
= lp_load(servicesf
,False
,False
,True
);
46 /* Print client information */
48 static void do_print_client_info(void)
50 struct winbindd_cli_state
*client
;
53 if (client_list
== NULL
) {
54 DEBUG(0, ("no clients in list\n"));
58 DEBUG(0, ("client list is:\n"));
60 for (client
= client_list
, i
= 0; client
; client
= client
->next
) {
61 DEBUG(0, ("client %3d: pid = %5d fd = %d read = %4d write = %4d\n",
62 i
, client
->pid
, client
->sock
, client
->read_buf_len
,
63 client
->write_buf_len
));
68 /* Flush client cache */
70 static void do_flush_caches(void)
72 /* Clear cached user and group enumation info */
74 winbindd_flush_cache();
77 /* Handle the signal by unlinking socket and exiting */
79 static void termination_handler(int signum
)
83 /* Remove socket file */
85 slprintf(path
, sizeof(path
), "%s/%s",
86 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
);
92 static BOOL print_client_info
;
94 static BOOL flush_cache
;
96 static void sighup_handler(int signum
)
98 BlockSignals(True
, SIGHUP
);
100 BlockSignals(False
, SIGHUP
);
103 /* Create winbindd socket */
105 static int create_sock(void)
107 struct sockaddr_un sunaddr
;
113 /* Create the socket directory or reuse the existing one */
115 if (lstat(WINBINDD_SOCKET_DIR
, &st
) == -1) {
117 if (errno
== ENOENT
) {
119 /* Create directory */
121 if (mkdir(WINBINDD_SOCKET_DIR
, 0755) == -1) {
122 DEBUG(0, ("error creating socket directory %s: %s\n",
123 WINBINDD_SOCKET_DIR
, sys_errlist
[errno
]));
129 DEBUG(0, ("lstat failed on socket directory %s: %s\n",
130 WINBINDD_SOCKET_DIR
, sys_errlist
[errno
]));
136 /* Check ownership and permission on existing directory */
138 if (!S_ISDIR(st
.st_mode
)) {
139 DEBUG(0, ("socket directory %s isn't a directory\n",
140 WINBINDD_SOCKET_DIR
));
144 if ((st
.st_uid
!= 0) || ((st
.st_mode
& 0777) != 0755)) {
145 DEBUG(0, ("invalid permissions on socket directory %s\n",
146 WINBINDD_SOCKET_DIR
));
151 /* Create the socket file */
153 old_umask
= umask(0);
155 sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
162 slprintf(path
, sizeof(path
), "%s/%s",
163 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
);
166 memset(&sunaddr
, 0, sizeof(sunaddr
));
167 sunaddr
.sun_family
= AF_UNIX
;
168 safe_strcpy(sunaddr
.sun_path
, path
, sizeof(sunaddr
.sun_path
)-1);
170 if (bind(sock
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
)) == -1) {
171 DEBUG(0, ("bind failed on winbind socket %s: %s\n",
173 sys_errlist
[errno
]));
178 if (listen(sock
, 5) == -1) {
179 DEBUG(0, ("listen failed on winbind socket %s: %s\n",
181 sys_errlist
[errno
]));
193 static void process_request(struct winbindd_cli_state
*state
)
195 /* Process command */
197 state
->response
.result
= WINBINDD_ERROR
;
198 state
->response
.length
= sizeof(struct winbindd_response
);
200 DEBUG(3,("processing command %s from pid %d\n",
201 winbindd_cmd_to_string(state
->request
.cmd
), state
->pid
));
203 if (!server_state
.lsa_handle_open
) return;
205 switch(state
->request
.cmd
) {
209 case WINBINDD_GETPWNAM_FROM_USER
:
210 state
->response
.result
= winbindd_getpwnam_from_user(state
);
213 case WINBINDD_GETPWNAM_FROM_UID
:
214 state
->response
.result
= winbindd_getpwnam_from_uid(state
);
217 case WINBINDD_SETPWENT
:
218 state
->response
.result
= winbindd_setpwent(state
);
221 case WINBINDD_ENDPWENT
:
222 state
->response
.result
= winbindd_endpwent(state
);
225 case WINBINDD_GETPWENT
:
226 state
->response
.result
= winbindd_getpwent(state
);
229 /* Group functions */
231 case WINBINDD_GETGRNAM_FROM_GROUP
:
232 state
->response
.result
= winbindd_getgrnam_from_group(state
);
235 case WINBINDD_GETGRNAM_FROM_GID
:
236 state
->response
.result
= winbindd_getgrnam_from_gid(state
);
239 case WINBINDD_SETGRENT
:
240 state
->response
.result
= winbindd_setgrent(state
);
243 case WINBINDD_ENDGRENT
:
244 state
->response
.result
= winbindd_endgrent(state
);
247 case WINBINDD_GETGRENT
:
248 state
->response
.result
= winbindd_getgrent(state
);
251 /* pam auth functions */
252 case WINBINDD_PAM_AUTH
:
253 state
->response
.result
= winbindd_pam_auth(state
);
259 DEBUG(0, ("oops - unknown winbindd command %d\n", state
->request
.cmd
));
264 /* Process a new connection by adding it to the client connection list */
266 static void new_connection(int accept_sock
)
268 struct sockaddr_un sunaddr
;
269 struct winbindd_cli_state
*state
;
272 /* Accept connection */
274 len
= sizeof(sunaddr
);
275 if ((sock
= accept(accept_sock
, (struct sockaddr
*)&sunaddr
, &len
))
281 DEBUG(6,("accepted socket %d\n", sock
));
283 /* Create new connection structure */
285 if ((state
= (struct winbindd_cli_state
*)
286 malloc(sizeof(*state
))) == NULL
) {
294 /* Add to connection list */
296 DLIST_ADD(client_list
, state
);
299 /* Remove a client connection from client connection list */
301 static void remove_client(struct winbindd_cli_state
*state
)
303 /* It's a dead client - hold a funeral */
311 /* Free any getent state */
313 free_getent_state(state
->getpwent_state
);
314 free_getent_state(state
->getgrent_state
);
316 /* Free any extra data */
318 safe_free(state
->response
.extra_data
);
320 /* Remove from list and free */
322 DLIST_REMOVE(client_list
, state
);
327 /* Process a complete received packet from a client */
329 static void process_packet(struct winbindd_cli_state
*state
)
331 /* Process request */
333 state
->pid
= state
->request
.pid
;
335 process_request(state
);
337 /* Update client state */
339 state
->read_buf_len
= 0;
340 state
->write_buf_len
= sizeof(state
->response
);
343 /* Read some data from a client connection */
345 static void client_read(struct winbindd_cli_state
*state
)
351 n
= read(state
->sock
, state
->read_buf_len
+ (char *)&state
->request
,
352 sizeof(state
->request
) - state
->read_buf_len
);
354 /* Read failed, kill client */
356 if (n
== -1 || n
== 0) {
357 DEBUG(5,("read failed on sock %d, pid %d: %s\n",
358 state
->sock
, state
->pid
,
359 (n
== -1) ? sys_errlist
[errno
] : "EOF"));
361 state
->finished
= True
;
365 /* Update client state */
367 state
->read_buf_len
+= n
;
370 /* Write some data to a client connection */
372 static void client_write(struct winbindd_cli_state
*state
)
379 if (state
->write_extra_data
) {
381 /* Write extra data */
383 data
= (char *)state
->response
.extra_data
+
384 state
->response
.length
- sizeof(struct winbindd_response
) -
385 state
->write_buf_len
;
389 /* Write response structure */
391 data
= (char *)&state
->response
+ sizeof(state
->response
) -
392 state
->write_buf_len
;
395 n
= write(state
->sock
, data
, state
->write_buf_len
);
397 /* Write failed, kill cilent */
399 if (n
== -1 || n
== 0) {
401 DEBUG(3,("write failed on sock %d, pid %d: %s\n",
402 state
->sock
, state
->pid
,
403 (n
== -1) ? sys_errlist
[errno
] : "EOF"));
405 state
->finished
= True
;
409 /* Update client state */
411 state
->write_buf_len
-= n
;
413 /* Have we written all data? */
415 if (state
->write_buf_len
== 0) {
417 /* Take care of extra data */
419 if (state
->response
.length
> sizeof(struct winbindd_response
)) {
421 if (state
->write_extra_data
) {
423 /* Already written extra data - free it */
425 safe_free(state
->response
.extra_data
);
426 state
->response
.extra_data
= NULL
;
427 state
->write_extra_data
= False
;
431 /* Start writing extra data */
433 state
->write_buf_len
= state
->response
.length
-
434 sizeof(struct winbindd_response
);
435 state
->write_extra_data
= True
;
441 /* Process incoming clients on accept_sock. We use a tricky non-blocking,
442 non-forking, non-threaded model which allows us to handle many
443 simultaneous connections while remaining impervious to many denial of
446 static void process_loop(int accept_sock
)
448 /* We'll be doing this a lot */
451 struct winbindd_cli_state
*state
;
453 int maxfd
= accept_sock
, selret
;
454 struct timeval timeout
;
456 /* do any connection establishment that is needed */
457 establish_connections();
459 /* Initialise fd lists for select() */
463 FD_SET(accept_sock
, &r_fds
);
465 timeout
.tv_sec
= WINBINDD_ESTABLISH_LOOP
;
468 /* Set up client readers and writers */
473 /* Dispose of client connection if it is marked as finished */
475 if (state
->finished
) {
476 struct winbindd_cli_state
*next
= state
->next
;
478 remove_client(state
);
483 /* Select requires we know the highest fd used */
485 if (state
->sock
> maxfd
) maxfd
= state
->sock
;
487 /* Add fd for reading */
489 if (state
->read_buf_len
!= sizeof(state
->request
)) {
490 FD_SET(state
->sock
, &r_fds
);
493 /* Add fd for writing */
495 if (state
->write_buf_len
) {
496 FD_SET(state
->sock
, &w_fds
);
502 /* Check signal handling things */
506 reload_services_file();
510 if (print_client_info
) {
511 do_print_client_info();
512 print_client_info
= False
;
517 selret
= select(maxfd
+ 1, &r_fds
, &w_fds
, NULL
, &timeout
);
519 if (selret
== 0) continue;
521 if ((selret
== -1 && errno
!= EINTR
) || selret
== 0) {
523 /* Select error, something is badly wrong */
529 /* Create a new connection if accept_sock readable */
533 if (FD_ISSET(accept_sock
, &r_fds
)) {
534 new_connection(accept_sock
);
537 /* Process activity on client connections */
539 for (state
= client_list
; state
; state
= state
->next
) {
541 /* Data available for reading */
543 if (FD_ISSET(state
->sock
, &r_fds
)) {
549 /* A request packet might be complete */
551 if (state
->read_buf_len
== sizeof(state
->request
)) {
552 process_packet(state
);
556 /* Data available for writing */
558 if (FD_ISSET(state
->sock
, &w_fds
)) {
568 struct winbindd_state server_state
; /* Server state information */
570 int main(int argc
, char **argv
)
572 extern pstring global_myname
;
573 extern pstring debugf
;
575 BOOL interactive
= False
;
578 while ((opt
= getopt(argc
, argv
, "i")) != EOF
) {
584 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
589 /* Initialise samba/rpc client stuff */
590 slprintf(debugf
, sizeof(debugf
), "%s/log.winbindd", LOGFILEBASE
);
591 setup_logging("winbindd", interactive
);
594 if (!*global_myname
) {
597 fstrcpy(global_myname
, myhostname());
598 p
= strchr(global_myname
, '.');
605 charset_initialise();
606 codepage_initialise(lp_client_code_page());
608 if (!lp_load(CONFIGFILE
, True
, False
, False
)) {
609 DEBUG(0, ("error opening config file\n"));
620 ZERO_STRUCT(server_state
);
622 /* Winbind daemon initialisation */
623 if (!winbindd_param_init()) {
627 if (!winbindd_idmap_init()) {
631 winbindd_cache_init();
633 /* Setup signal handlers */
635 CatchSignal(SIGINT
, termination_handler
); /* Exit on these sigs */
636 CatchSignal(SIGQUIT
, termination_handler
);
637 CatchSignal(SIGTERM
, termination_handler
);
639 CatchSignal(SIGPIPE
, SIG_IGN
); /* Ignore sigpipe */
641 CatchSignal(SIGHUP
, sighup_handler
);
643 /* Create UNIX domain socket */
645 if ((accept_sock
= create_sock()) == -1) {
646 DEBUG(0, ("failed to create socket\n"));
650 /* Loop waiting for requests */
652 process_loop(accept_sock
);