f31a4f2de4d06855fad3ee84dedb8ca681de6e12
[kai/samba.git] / source3 / nsswitch / winbindd_dual.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind background daemon
5
6    Copyright (C) Andrew Tridgell 2002
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24   the idea of the optional dual daemon mode is ot prevent slow domain
25   responses from clagging up the rest of the system. When in dual
26   daemon mode winbindd always responds to requests from cache if the
27   request is in cache, and if the cached answer is stale then it asks
28   the "dual daemon" to update the cache for that request
29
30  */
31
32 #include "winbindd.h"
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_WINBIND
36
37 extern BOOL opt_dual_daemon;
38 BOOL background_process = False;
39 int dual_daemon_pipe = -1;
40
41
42 /* a list of requests ready to be sent to the dual daemon */
43 struct dual_list {
44         struct dual_list *next;
45         char *data;
46         int length;
47         int offset;
48 };
49
50 static struct dual_list *dual_list;
51 static struct dual_list *dual_list_end;
52
53 /*
54   setup a select() including the dual daemon pipe
55  */
56 int dual_select_setup(fd_set *fds, int maxfd)
57 {
58         if (dual_daemon_pipe == -1 ||
59             !dual_list) {
60                 return maxfd;
61         }
62
63         FD_SET(dual_daemon_pipe, fds);
64         if (dual_daemon_pipe > maxfd) {
65                 maxfd = dual_daemon_pipe;
66         }
67         return maxfd;
68 }
69
70
71 /*
72   a hook called from the main winbindd select() loop to handle writes
73   to the dual daemon pipe 
74 */
75 void dual_select(fd_set *fds)
76 {
77         int n;
78
79         if (dual_daemon_pipe == -1 ||
80             !dual_list ||
81             !FD_ISSET(dual_daemon_pipe, fds)) {
82                 return;
83         }
84
85         n = sys_write(dual_daemon_pipe, 
86                   &dual_list->data[dual_list->offset],
87                   dual_list->length - dual_list->offset);
88
89         if (n <= 0) {
90                 /* the pipe is dead! fall back to normal operation */
91                 dual_daemon_pipe = -1;
92                 return;
93         }
94
95         dual_list->offset += n;
96
97         if (dual_list->offset == dual_list->length) {
98                 struct dual_list *next;
99                 next = dual_list->next;
100                 free(dual_list->data);
101                 free(dual_list);
102                 dual_list = next;
103                 if (!dual_list) {
104                         dual_list_end = NULL;
105                 }
106         }
107 }
108
109 /* 
110    send a request to the background daemon 
111    this is called for stale cached entries
112 */
113 void dual_send_request(struct winbindd_cli_state *state)
114 {
115         struct dual_list *list;
116
117         if (!background_process) return;
118
119         list = malloc(sizeof(*list));
120         if (!list) return;
121
122         list->next = NULL;
123         list->data = memdup(&state->request, sizeof(state->request));
124         list->length = sizeof(state->request);
125         list->offset = 0;
126         
127         if (!dual_list_end) {
128                 dual_list = list;
129                 dual_list_end = list;
130         } else {
131                 dual_list_end->next = list;
132                 dual_list_end = list;
133         }
134
135         background_process = False;
136 }
137
138
139 /* 
140 the main dual daemon 
141 */
142 void do_dual_daemon(void)
143 {
144         int fdpair[2];
145         struct winbindd_cli_state state;
146         
147         if (pipe(fdpair) != 0) {
148                 return;
149         }
150
151         ZERO_STRUCT(state);
152         state.pid = getpid();
153
154         dual_daemon_pipe = fdpair[1];
155         state.sock = fdpair[0];
156
157         if (fork() != 0) {
158                 close(fdpair[0]);
159                 return;
160         }
161         close(fdpair[1]);
162
163         
164         sleep (60);
165         DEBUG(0,("do_dual_daemon: Starting up....\n"));
166         
167         if (!winbind_setup_common()) 
168                 _exit(0);
169
170         dual_daemon_pipe = -1;
171         opt_dual_daemon = False;
172
173         while (1) {
174                 /* free up any talloc memory */
175                 lp_talloc_free();
176                 main_loop_talloc_free();
177
178                 /* fetch a request from the main daemon */
179                 winbind_client_read(&state);
180
181                 if (state.finished) {
182                         /* we lost contact with our parent */
183                         exit(0);
184                 }
185
186                 /* process full rquests */
187                 if (state.read_buf_len == sizeof(state.request)) {
188                         DEBUG(4,("dual daemon request %d\n", (int)state.request.cmd));
189
190                         /* special handling for the stateful requests */
191                         switch (state.request.cmd) {
192                         case WINBINDD_GETPWENT:
193                                 winbindd_setpwent(&state);
194                                 break;
195                                 
196                         case WINBINDD_GETGRENT:
197                         case WINBINDD_GETGRLST:
198                                 winbindd_setgrent(&state);
199                                 break;
200                         default:
201                                 break;
202                         }
203
204                         winbind_process_packet(&state);
205                         SAFE_FREE(state.response.extra_data);
206
207                         free_getent_state(state.getpwent_state);
208                         free_getent_state(state.getgrent_state);
209                         state.getpwent_state = NULL;
210                         state.getgrent_state = NULL;
211                 }
212         }
213 }
214