perl script to autogenerate metrics.h file from profile.h
[Samba.git] / source / nsswitch / winbindd.c
blob7af1d09723be1364f672e7c412cb35a968fec10b
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.0
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.
24 #include "winbindd.h"
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;
35 BOOL ret;
37 reopen_logs();
38 ret = lp_load(servicesf,False,False,True);
40 reopen_logs();
41 load_interfaces();
43 return(ret);
46 /* Print client information */
48 static void do_print_client_info(void)
50 struct winbindd_cli_state *client;
51 int i;
53 if (client_list == NULL) {
54 DEBUG(0, ("no clients in list\n"));
55 return;
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));
64 i++;
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)
81 pstring path;
83 /* Remove socket file */
85 slprintf(path, sizeof(path), "%s/%s",
86 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
87 unlink(path);
89 exit(0);
92 static BOOL print_client_info;
94 static BOOL flush_cache;
96 static void sighup_handler(int signum)
98 BlockSignals(True, SIGHUP);
99 flush_cache = True;
100 BlockSignals(False, SIGHUP);
103 /* Create winbindd socket */
105 static int create_sock(void)
107 struct sockaddr_un sunaddr;
108 struct stat st;
109 int sock;
110 mode_t old_umask;
111 pstring path;
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]));
124 return -1;
127 } else {
129 DEBUG(0, ("lstat failed on socket directory %s: %s\n",
130 WINBINDD_SOCKET_DIR, sys_errlist[errno]));
131 return -1;
134 } else {
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));
141 return -1;
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));
147 return -1;
151 /* Create the socket file */
153 old_umask = umask(0);
155 sock = socket(AF_UNIX, SOCK_STREAM, 0);
157 if (sock == -1) {
158 perror("socket");
159 return -1;
162 slprintf(path, sizeof(path), "%s/%s",
163 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
165 unlink(path);
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",
172 path,
173 sys_errlist[errno]));
174 close(sock);
175 return -1;
178 if (listen(sock, 5) == -1) {
179 DEBUG(0, ("listen failed on winbind socket %s: %s\n",
180 path,
181 sys_errlist[errno]));
182 close(sock);
183 return -1;
186 umask(old_umask);
188 /* Success! */
190 return sock;
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) {
207 /* User functions */
209 case WINBINDD_GETPWNAM_FROM_USER:
210 state->response.result = winbindd_getpwnam_from_user(state);
211 break;
213 case WINBINDD_GETPWNAM_FROM_UID:
214 state->response.result = winbindd_getpwnam_from_uid(state);
215 break;
217 case WINBINDD_SETPWENT:
218 state->response.result = winbindd_setpwent(state);
219 break;
221 case WINBINDD_ENDPWENT:
222 state->response.result = winbindd_endpwent(state);
223 break;
225 case WINBINDD_GETPWENT:
226 state->response.result = winbindd_getpwent(state);
227 break;
229 /* Group functions */
231 case WINBINDD_GETGRNAM_FROM_GROUP:
232 state->response.result = winbindd_getgrnam_from_group(state);
233 break;
235 case WINBINDD_GETGRNAM_FROM_GID:
236 state->response.result = winbindd_getgrnam_from_gid(state);
237 break;
239 case WINBINDD_SETGRENT:
240 state->response.result = winbindd_setgrent(state);
241 break;
243 case WINBINDD_ENDGRENT:
244 state->response.result = winbindd_endgrent(state);
245 break;
247 case WINBINDD_GETGRENT:
248 state->response.result = winbindd_getgrent(state);
249 break;
251 /* pam auth functions */
252 case WINBINDD_PAM_AUTH:
253 state->response.result = winbindd_pam_auth(state);
254 break;
256 /* Oops */
258 default:
259 DEBUG(0, ("oops - unknown winbindd command %d\n", state->request.cmd));
260 break;
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;
270 int len, sock;
272 /* Accept connection */
274 len = sizeof(sunaddr);
275 if ((sock = accept(accept_sock, (struct sockaddr *)&sunaddr, &len))
276 == -1) {
278 return;
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) {
288 return;
291 ZERO_STRUCTP(state);
292 state->sock = sock;
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 */
305 if (state != NULL) {
307 /* Close socket */
309 close(state->sock);
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);
323 free(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)
347 int n;
349 /* Read data */
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;
362 return;
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)
374 char *data;
375 int n;
377 /* Write data */
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;
387 } else {
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;
406 return;
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;
429 } else {
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
444 service attacks. */
446 static void process_loop(int accept_sock)
448 /* We'll be doing this a lot */
450 while (1) {
451 struct winbindd_cli_state *state;
452 fd_set r_fds, w_fds;
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() */
461 FD_ZERO(&r_fds);
462 FD_ZERO(&w_fds);
463 FD_SET(accept_sock, &r_fds);
465 timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
466 timeout.tv_usec = 0;
468 /* Set up client readers and writers */
470 state = client_list;
472 while (state) {
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);
479 state = next;
480 continue;
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);
499 state = state->next;
502 /* Check signal handling things */
504 if (flush_cache) {
505 do_flush_caches();
506 reload_services_file();
507 flush_cache = False;
510 if (print_client_info) {
511 do_print_client_info();
512 print_client_info = False;
515 /* Call select */
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 */
525 perror("select");
526 exit(1);
529 /* Create a new connection if accept_sock readable */
531 if (selret > 0) {
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)) {
545 /* Read data */
547 client_read(state);
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)) {
559 client_write(state);
566 /* Main function */
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;
574 int accept_sock;
575 BOOL interactive = False;
576 int opt;
578 while ((opt = getopt(argc, argv, "i")) != EOF) {
579 switch (opt) {
580 case 'i':
581 interactive = True;
582 break;
583 default:
584 printf("Unknown option %c (%d)\n", (char)opt, opt);
585 exit(1);
589 /* Initialise samba/rpc client stuff */
590 slprintf(debugf, sizeof(debugf), "%s/log.winbindd", LOGFILEBASE);
591 setup_logging("winbindd", interactive);
592 reopen_logs();
594 if (!*global_myname) {
595 char *p;
597 fstrcpy(global_myname, myhostname());
598 p = strchr(global_myname, '.');
599 if (p) {
600 *p = 0;
604 TimeInit();
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"));
610 exit(1);
613 if (!interactive) {
614 become_daemon();
616 load_interfaces();
618 secrets_init();
620 ZERO_STRUCT(server_state);
622 /* Winbind daemon initialisation */
623 if (!winbindd_param_init()) {
624 return 1;
627 if (!winbindd_idmap_init()) {
628 return 1;
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"));
647 return 1;
650 /* Loop waiting for requests */
652 process_loop(accept_sock);
654 return 0;