d4ec6e586db29510a28252ac9de961ea3cf63492
[tprouty/samba.git] / source / 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 "includes.h"
33 #include "winbindd.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_WINBIND
37
38 extern BOOL opt_dual_daemon;
39 BOOL background_process = False;
40 int dual_daemon_pipe = -1;
41
42
43 /* a list of requests ready to be sent to the dual daemon */
44 struct dual_list {
45         struct dual_list *next;
46         char *data;
47         int length;
48         int offset;
49 };
50
51 static struct dual_list *dual_list;
52 static struct dual_list *dual_list_end;
53
54 /*
55   setup a select() including the dual daemon pipe
56  */
57 int dual_select_setup(fd_set *fds, int maxfd)
58 {
59         if (dual_daemon_pipe == -1 ||
60             !dual_list) {
61                 return maxfd;
62         }
63
64         FD_SET(dual_daemon_pipe, fds);
65         if (dual_daemon_pipe > maxfd) {
66                 maxfd = dual_daemon_pipe;
67         }
68         return maxfd;
69 }
70
71
72 /*
73   a hook called from the main winbindd select() loop to handle writes
74   to the dual daemon pipe 
75 */
76 void dual_select(fd_set *fds)
77 {
78         int n;
79
80         if (dual_daemon_pipe == -1 ||
81             !dual_list ||
82             !FD_ISSET(dual_daemon_pipe, fds)) {
83                 return;
84         }
85
86         n = sys_write(dual_daemon_pipe, 
87                   &dual_list->data[dual_list->offset],
88                   dual_list->length - dual_list->offset);
89
90         if (n <= 0) {
91                 /* the pipe is dead! fall back to normal operation */
92                 dual_daemon_pipe = -1;
93                 return;
94         }
95
96         dual_list->offset += n;
97
98         if (dual_list->offset == dual_list->length) {
99                 struct dual_list *next;
100                 next = dual_list->next;
101                 free(dual_list->data);
102                 free(dual_list);
103                 dual_list = next;
104                 if (!dual_list) {
105                         dual_list_end = NULL;
106                 }
107         }
108 }
109
110 /* 
111    send a request to the background daemon 
112    this is called for stale cached entries
113 */
114 void dual_send_request(struct winbindd_cli_state *state)
115 {
116         struct dual_list *list;
117
118         if (!background_process) return;
119
120         list = malloc(sizeof(*list));
121         if (!list) return;
122
123         list->next = NULL;
124         list->data = memdup(&state->request, sizeof(state->request));
125         list->length = sizeof(state->request);
126         list->offset = 0;
127         
128         if (!dual_list_end) {
129                 dual_list = list;
130                 dual_list_end = list;
131         } else {
132                 dual_list_end->next = list;
133                 dual_list_end = list;
134         }
135
136         background_process = False;
137 }
138
139
140 /* 
141 the main dual daemon 
142 */
143 void do_dual_daemon(void)
144 {
145         int fdpair[2];
146         struct winbindd_cli_state state;
147         
148         if (pipe(fdpair) != 0) {
149                 return;
150         }
151
152         ZERO_STRUCT(state);
153         state.pid = getpid();
154
155         dual_daemon_pipe = fdpair[1];
156         state.sock = fdpair[0];
157
158         if (sys_fork() != 0) {
159                 close(fdpair[0]);
160                 return;
161         }
162         close(fdpair[1]);
163
164         /* tdb needs special fork handling */
165         if (tdb_reopen_all() == -1) {
166                 DEBUG(0,("tdb_reopen_all failed.\n"));
167                 _exit(0);
168         }
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