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 38extern BOOL opt_dual_daemon; 39BOOL background_process = False; 40int dual_daemon_pipe = -1; 41 42 43/* a list of requests ready to be sent to the dual daemon */ 44struct dual_list { 45 struct dual_list *next; 46 char *data; 47 int length; 48 int offset; 49}; 50 51static struct dual_list *dual_list; 52static struct dual_list *dual_list_end; 53 54/* 55 setup a select() including the dual daemon pipe 56 */ 57int 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*/ 76void 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*/ 114void dual_send_request(struct winbindd_cli_state *state) 115{ 116 struct dual_list *list; 117 118 if (!background_process) return; 119 120 list = SMB_MALLOC_P(struct dual_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/* 141the main dual daemon 142*/ 143void 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 215