this is a trick to work around the fact that posix does not supply
[ira/wip.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 backgroud_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 = 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 (!backgroud_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         backgroud_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         if (winbind_setup_common() != 0) _exit(0);
164
165         dual_daemon_pipe = -1;
166         opt_dual_daemon = False;
167
168         while (1) {
169                 /* free up any talloc memory */
170                 lp_talloc_free();
171                 main_loop_talloc_free();
172
173                 /* fetch a request from the main daemon */
174                 winbind_client_read(&state);
175
176                 if (state.finished) {
177                         /* we lost contact with our parent */
178                         exit(0);
179                 }
180
181                 /* process full rquests */
182                 if (state.read_buf_len == sizeof(state.request)) {
183                         DEBUG(4,("dual daemon request %d\n", (int)state.request.cmd));
184
185                         /* special handling for the stateful requests */
186                         switch (state.request.cmd) {
187                         case WINBINDD_GETPWENT:
188                                 winbindd_setpwent(&state);
189                                 break;
190                                 
191                         case WINBINDD_GETGRENT:
192                         case WINBINDD_GETGRLST:
193                                 winbindd_setgrent(&state);
194                                 break;
195                         default:
196                                 break;
197                         }
198
199                         winbind_process_packet(&state);
200                         SAFE_FREE(state.response.extra_data);
201
202                         free_getent_state(state.getpwent_state);
203                         free_getent_state(state.getgrent_state);
204                         state.getpwent_state = NULL;
205                         state.getgrent_state = NULL;
206                 }
207         }
208 }
209