nsswitch/winbindd.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind daemon for ntdom nss module
00005 
00006    Copyright (C) by Tim Potter 2000-2002
00007    Copyright (C) Andrew Tridgell 2002
00008    Copyright (C) Jelmer Vernooij 2003
00009    Copyright (C) Volker Lendecke 2004
00010    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015    
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020    
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 */
00025 
00026 #include "includes.h"
00027 #include "winbindd.h"
00028 
00029 #undef DBGC_CLASS
00030 #define DBGC_CLASS DBGC_WINBIND
00031 
00032 BOOL opt_nocache = False;
00033 static BOOL interactive = False;
00034 
00035 extern BOOL override_logfile;
00036 
00037 struct event_context *winbind_event_context(void)
00038 {
00039         static struct event_context *ctx;
00040 
00041         if (!ctx && !(ctx = event_context_init(NULL))) {
00042                 smb_panic("Could not init winbind event context\n");
00043         }
00044         return ctx;
00045 }
00046 
00047 /* Reload configuration */
00048 
00049 static BOOL reload_services_file(const char *logfile)
00050 {
00051         BOOL ret;
00052 
00053         if (lp_loaded()) {
00054                 pstring fname;
00055 
00056                 pstrcpy(fname,lp_configfile());
00057                 if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) {
00058                         pstrcpy(dyn_CONFIGFILE,fname);
00059                 }
00060         }
00061 
00062         reopen_logs();
00063         ret = lp_load(dyn_CONFIGFILE,False,False,True,True);
00064 
00065         /* if this is a child, restore the logfile to the special
00066            name - <domain>, idmap, etc. */
00067         if (logfile && *logfile)
00068                 lp_set_logfile(logfile);
00069 
00070         reopen_logs();
00071         load_interfaces();
00072 
00073         return(ret);
00074 }
00075 
00076 
00077 /**************************************************************************** **
00078  Handle a fault..
00079  **************************************************************************** */
00080 
00081 static void fault_quit(void)
00082 {
00083         dump_core();
00084 }
00085 
00086 static void winbindd_status(void)
00087 {
00088         struct winbindd_cli_state *tmp;
00089 
00090         DEBUG(0, ("winbindd status:\n"));
00091 
00092         /* Print client state information */
00093         
00094         DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients()));
00095         
00096         if (DEBUGLEVEL >= 2 && winbindd_num_clients()) {
00097                 DEBUG(2, ("\tclient list:\n"));
00098                 for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) {
00099                         DEBUGADD(2, ("\t\tpid %lu, sock %d\n",
00100                                   (unsigned long)tmp->pid, tmp->sock));
00101                 }
00102         }
00103 }
00104 
00105 /* Print winbindd status to log file */
00106 
00107 static void print_winbindd_status(void)
00108 {
00109         winbindd_status();
00110 }
00111 
00112 /* Flush client cache */
00113 
00114 static void flush_caches(void)
00115 {
00116         /* We need to invalidate cached user list entries on a SIGHUP 
00117            otherwise cached access denied errors due to restrict anonymous
00118            hang around until the sequence number changes. */
00119 
00120         wcache_invalidate_cache();
00121 }
00122 
00123 /* Handle the signal by unlinking socket and exiting */
00124 
00125 static void terminate(bool in_parent)
00126 {
00127         if (in_parent) {
00128                 /* When parent goes away we should
00129                  * remove the socket file. Not so
00130                  * when children terminate.
00131                  */ 
00132 
00133                 pstring path;
00134 
00135                 /* Remove socket file */
00136                 pstr_sprintf(path, "%s/%s", 
00137                         WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
00138                 unlink(path);
00139         }
00140 
00141         idmap_close();
00142         
00143         trustdom_cache_shutdown();
00144 
00145 #if 0
00146         if (interactive) {
00147                 TALLOC_CTX *mem_ctx = talloc_init("end_description");
00148                 char *description = talloc_describe_all(mem_ctx);
00149 
00150                 DEBUG(3, ("tallocs left:\n%s\n", description));
00151                 talloc_destroy(mem_ctx);
00152         }
00153 #endif
00154 
00155         exit(0);
00156 }
00157 
00158 static BOOL do_sigterm;
00159 
00160 static void termination_handler(int signum)
00161 {
00162         do_sigterm = True;
00163         sys_select_signal(signum);
00164 }
00165 
00166 static BOOL do_sigusr2;
00167 
00168 static void sigusr2_handler(int signum)
00169 {
00170         do_sigusr2 = True;
00171         sys_select_signal(SIGUSR2);
00172 }
00173 
00174 static BOOL do_sighup;
00175 
00176 static void sighup_handler(int signum)
00177 {
00178         do_sighup = True;
00179         sys_select_signal(SIGHUP);
00180 }
00181 
00182 static BOOL do_sigchld;
00183 
00184 static void sigchld_handler(int signum)
00185 {
00186         do_sigchld = True;
00187         sys_select_signal(SIGCHLD);
00188 }
00189 
00190 /* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
00191 static void msg_reload_services(int msg_type, struct process_id src,
00192                                 void *buf, size_t len, void *private_data)
00193 {
00194         /* Flush various caches */
00195         flush_caches();
00196         reload_services_file((const char *) private_data);
00197 }
00198 
00199 /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
00200 static void msg_shutdown(int msg_type, struct process_id src,
00201                          void *buf, size_t len, void *private_data)
00202 {
00203         do_sigterm = True;
00204 }
00205 
00206 static struct winbindd_dispatch_table {
00207         enum winbindd_cmd cmd;
00208         void (*fn)(struct winbindd_cli_state *state);
00209         const char *winbindd_cmd_name;
00210 } dispatch_table[] = {
00211         
00212         /* User functions */
00213 
00214         { WINBINDD_GETPWNAM, winbindd_getpwnam, "GETPWNAM" },
00215         { WINBINDD_GETPWUID, winbindd_getpwuid, "GETPWUID" },
00216 
00217         { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" },
00218         { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" },
00219         { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" },
00220 
00221         { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
00222         { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
00223         { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups,
00224           "GETUSERDOMGROUPS" },
00225 
00226         /* Group functions */
00227 
00228         { WINBINDD_GETGRNAM, winbindd_getgrnam, "GETGRNAM" },
00229         { WINBINDD_GETGRGID, winbindd_getgrgid, "GETGRGID" },
00230         { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" },
00231         { WINBINDD_ENDGRENT, winbindd_endgrent, "ENDGRENT" },
00232         { WINBINDD_GETGRENT, winbindd_getgrent, "GETGRENT" },
00233         { WINBINDD_GETGRLST, winbindd_getgrent, "GETGRLST" },
00234 
00235         /* PAM auth functions */
00236 
00237         { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
00238         { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
00239         { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
00240         { WINBINDD_PAM_LOGOFF, winbindd_pam_logoff, "PAM_LOGOFF" },
00241         { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, winbindd_pam_chng_pswd_auth_crap, "CHNG_PSWD_AUTH_CRAP" },
00242 
00243         /* Enumeration functions */
00244 
00245         { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
00246         { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
00247         { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
00248           "LIST_TRUSTDOM" },
00249         { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" },
00250 
00251         /* SID related functions */
00252 
00253         { WINBINDD_LOOKUPSID, winbindd_lookupsid, "LOOKUPSID" },
00254         { WINBINDD_LOOKUPNAME, winbindd_lookupname, "LOOKUPNAME" },
00255         { WINBINDD_LOOKUPRIDS, winbindd_lookuprids, "LOOKUPRIDS" },
00256 
00257         /* Lookup related functions */
00258 
00259         { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
00260         { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
00261         { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
00262         { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
00263 #if 0   /* DISABLED until we fix the interface in Samba 3.0.26 --jerry */
00264         { WINBINDD_SIDS_TO_XIDS, winbindd_sids_to_unixids, "SIDS_TO_XIDS" },
00265 #endif  /* end DISABLED */
00266         { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" },
00267         { WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" },
00268         { WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" },
00269         { WINBINDD_SET_HWM, winbindd_set_hwm, "SET_HWMS" },
00270 
00271         /* Miscellaneous */
00272 
00273         { WINBINDD_DUMP_MAPS, winbindd_dump_maps, "DUMP_MAPS" },
00274 
00275         { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
00276         { WINBINDD_PING, winbindd_ping, "PING" },
00277         { WINBINDD_INFO, winbindd_info, "INFO" },
00278         { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
00279           "INTERFACE_VERSION" },
00280         { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
00281         { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
00282         { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
00283         { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
00284           "WINBINDD_PRIV_PIPE_DIR" },
00285         { WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" },
00286 
00287         /* Credential cache access */
00288         { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" },
00289 
00290         /* WINS functions */
00291 
00292         { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" },
00293         { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" },
00294         
00295         /* End of list */
00296 
00297         { WINBINDD_NUM_CMDS, NULL, "NONE" }
00298 };
00299 
00300 static void process_request(struct winbindd_cli_state *state)
00301 {
00302         struct winbindd_dispatch_table *table = dispatch_table;
00303 
00304         /* Free response data - we may be interrupted and receive another
00305            command before being able to send this data off. */
00306 
00307         SAFE_FREE(state->response.extra_data.data);  
00308 
00309         ZERO_STRUCT(state->response);
00310 
00311         state->response.result = WINBINDD_PENDING;
00312         state->response.length = sizeof(struct winbindd_response);
00313 
00314         state->mem_ctx = talloc_init("winbind request");
00315         if (state->mem_ctx == NULL)
00316                 return;
00317 
00318         /* Remember who asked us. */
00319         state->pid = state->request.pid;
00320 
00321         /* Process command */
00322 
00323         for (table = dispatch_table; table->fn; table++) {
00324                 if (state->request.cmd == table->cmd) {
00325                         DEBUG(10,("process_request: request fn %s\n",
00326                                   table->winbindd_cmd_name ));
00327                         table->fn(state);
00328                         break;
00329                 }
00330         }
00331 
00332         if (!table->fn) {
00333                 DEBUG(10,("process_request: unknown request fn number %d\n",
00334                           (int)state->request.cmd ));
00335                 request_error(state);
00336         }
00337 }
00338 
00339 /*
00340  * A list of file descriptors being monitored by select in the main processing
00341  * loop. fd_event->handler is called whenever the socket is readable/writable.
00342  */
00343 
00344 static struct fd_event *fd_events = NULL;
00345 
00346 void add_fd_event(struct fd_event *ev)
00347 {
00348         struct fd_event *match;
00349 
00350         /* only add unique fd_event structs */
00351 
00352         for (match=fd_events; match; match=match->next ) {
00353 #ifdef DEVELOPER
00354                 SMB_ASSERT( match != ev );
00355 #else
00356                 if ( match == ev )
00357                         return;
00358 #endif
00359         }
00360 
00361         DLIST_ADD(fd_events, ev);
00362 }
00363 
00364 void remove_fd_event(struct fd_event *ev)
00365 {
00366         DLIST_REMOVE(fd_events, ev);
00367 }
00368 
00369 /*
00370  * Handler for fd_events to complete a read/write request, set up by
00371  * setup_async_read/setup_async_write.
00372  */
00373 
00374 static void rw_callback(struct fd_event *event, int flags)
00375 {
00376         size_t todo;
00377         ssize_t done = 0;
00378 
00379         todo = event->length - event->done;
00380 
00381         if (event->flags & EVENT_FD_WRITE) {
00382                 SMB_ASSERT(flags == EVENT_FD_WRITE);
00383                 done = sys_write(event->fd,
00384                                  &((char *)event->data)[event->done],
00385                                  todo);
00386 
00387                 if (done <= 0) {
00388                         event->flags = 0;
00389                         event->finished(event->private_data, False);
00390                         return;
00391                 }
00392         }
00393 
00394         if (event->flags & EVENT_FD_READ) {
00395                 SMB_ASSERT(flags == EVENT_FD_READ);
00396                 done = sys_read(event->fd, &((char *)event->data)[event->done],
00397                                 todo);
00398 
00399                 if (done <= 0) {
00400                         event->flags = 0;
00401                         event->finished(event->private_data, False);
00402                         return;
00403                 }
00404         }
00405 
00406         event->done += done;
00407 
00408         if (event->done == event->length) {
00409                 event->flags = 0;
00410                 event->finished(event->private_data, True);
00411         }
00412 }
00413 
00414 /*
00415  * Request an async read/write on a fd_event structure. (*finished) is called
00416  * when the request is completed or an error had occurred.
00417  */
00418 
00419 void setup_async_read(struct fd_event *event, void *data, size_t length,
00420                       void (*finished)(void *private_data, BOOL success),
00421                       void *private_data)
00422 {
00423         SMB_ASSERT(event->flags == 0);
00424         event->data = data;
00425         event->length = length;
00426         event->done = 0;
00427         event->handler = rw_callback;
00428         event->finished = finished;
00429         event->private_data = private_data;
00430         event->flags = EVENT_FD_READ;
00431 }
00432 
00433 void setup_async_write(struct fd_event *event, void *data, size_t length,
00434                        void (*finished)(void *private_data, BOOL success),
00435                        void *private_data)
00436 {
00437         SMB_ASSERT(event->flags == 0);
00438         event->data = data;
00439         event->length = length;
00440         event->done = 0;
00441         event->handler = rw_callback;
00442         event->finished = finished;
00443         event->private_data = private_data;
00444         event->flags = EVENT_FD_WRITE;
00445 }
00446 
00447 /*
00448  * This is the main event loop of winbind requests. It goes through a
00449  * state-machine of 3 read/write requests, 4 if you have extra data to send.
00450  *
00451  * An idle winbind client has a read request of 4 bytes outstanding,
00452  * finalizing function is request_len_recv, checking the length. request_recv
00453  * then processes the packet. The processing function then at some point has
00454  * to call request_finished which schedules sending the response.
00455  */
00456 
00457 static void request_len_recv(void *private_data, BOOL success);
00458 static void request_recv(void *private_data, BOOL success);
00459 static void request_main_recv(void *private_data, BOOL success);
00460 static void request_finished(struct winbindd_cli_state *state);
00461 void request_finished_cont(void *private_data, BOOL success);
00462 static void response_main_sent(void *private_data, BOOL success);
00463 static void response_extra_sent(void *private_data, BOOL success);
00464 
00465 static void response_extra_sent(void *private_data, BOOL success)
00466 {
00467         struct winbindd_cli_state *state =
00468                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00469 
00470         if (state->mem_ctx != NULL) {
00471                 talloc_destroy(state->mem_ctx);
00472                 state->mem_ctx = NULL;
00473         }
00474 
00475         if (!success) {
00476                 state->finished = True;
00477                 return;
00478         }
00479 
00480         SAFE_FREE(state->request.extra_data.data);
00481         SAFE_FREE(state->response.extra_data.data);
00482 
00483         setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
00484                          request_len_recv, state);
00485 }
00486 
00487 static void response_main_sent(void *private_data, BOOL success)
00488 {
00489         struct winbindd_cli_state *state =
00490                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00491 
00492         if (!success) {
00493                 state->finished = True;
00494                 return;
00495         }
00496 
00497         if (state->response.length == sizeof(state->response)) {
00498                 if (state->mem_ctx != NULL) {
00499                         talloc_destroy(state->mem_ctx);
00500                         state->mem_ctx = NULL;
00501                 }
00502 
00503                 setup_async_read(&state->fd_event, &state->request,
00504                                  sizeof(uint32), request_len_recv, state);
00505                 return;
00506         }
00507 
00508         setup_async_write(&state->fd_event, state->response.extra_data.data,
00509                           state->response.length - sizeof(state->response),
00510                           response_extra_sent, state);
00511 }
00512 
00513 static void request_finished(struct winbindd_cli_state *state)
00514 {
00515         setup_async_write(&state->fd_event, &state->response,
00516                           sizeof(state->response), response_main_sent, state);
00517 }
00518 
00519 void request_error(struct winbindd_cli_state *state)
00520 {
00521         SMB_ASSERT(state->response.result == WINBINDD_PENDING);
00522         state->response.result = WINBINDD_ERROR;
00523         request_finished(state);
00524 }
00525 
00526 void request_ok(struct winbindd_cli_state *state)
00527 {
00528         SMB_ASSERT(state->response.result == WINBINDD_PENDING);
00529         state->response.result = WINBINDD_OK;
00530         request_finished(state);
00531 }
00532 
00533 void request_finished_cont(void *private_data, BOOL success)
00534 {
00535         struct winbindd_cli_state *state =
00536                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00537 
00538         if (success)
00539                 request_ok(state);
00540         else
00541                 request_error(state);
00542 }
00543 
00544 static void request_len_recv(void *private_data, BOOL success)
00545 {
00546         struct winbindd_cli_state *state =
00547                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00548 
00549         if (!success) {
00550                 state->finished = True;
00551                 return;
00552         }
00553 
00554         if (*(uint32 *)(&state->request) != sizeof(state->request)) {
00555                 DEBUG(0,("request_len_recv: Invalid request size received: %d (expected %d)\n",
00556                          *(uint32 *)(&state->request), (uint32)sizeof(state->request)));
00557                 state->finished = True;
00558                 return;
00559         }
00560 
00561         setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1,
00562                          sizeof(state->request) - sizeof(uint32),
00563                          request_main_recv, state);
00564 }
00565 
00566 static void request_main_recv(void *private_data, BOOL success)
00567 {
00568         struct winbindd_cli_state *state =
00569                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00570 
00571         if (!success) {
00572                 state->finished = True;
00573                 return;
00574         }
00575 
00576         if (state->request.extra_len == 0) {
00577                 state->request.extra_data.data = NULL;
00578                 request_recv(state, True);
00579                 return;
00580         }
00581 
00582         if ((!state->privileged) &&
00583             (state->request.extra_len > WINBINDD_MAX_EXTRA_DATA)) {
00584                 DEBUG(3, ("Got request with %d bytes extra data on "
00585                           "unprivileged socket\n", (int)state->request.extra_len));
00586                 state->request.extra_data.data = NULL;
00587                 state->finished = True;
00588                 return;
00589         }
00590 
00591         state->request.extra_data.data =
00592                 SMB_MALLOC_ARRAY(char, state->request.extra_len + 1);
00593 
00594         if (state->request.extra_data.data == NULL) {
00595                 DEBUG(0, ("malloc failed\n"));
00596                 state->finished = True;
00597                 return;
00598         }
00599 
00600         /* Ensure null termination */
00601         state->request.extra_data.data[state->request.extra_len] = '\0';
00602 
00603         setup_async_read(&state->fd_event, state->request.extra_data.data,
00604                          state->request.extra_len, request_recv, state);
00605 }
00606 
00607 static void request_recv(void *private_data, BOOL success)
00608 {
00609         struct winbindd_cli_state *state =
00610                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
00611 
00612         if (!success) {
00613                 state->finished = True;
00614                 return;
00615         }
00616 
00617         process_request(state);
00618 }
00619 
00620 /* Process a new connection by adding it to the client connection list */
00621 
00622 static void new_connection(int listen_sock, BOOL privileged)
00623 {
00624         struct sockaddr_un sunaddr;
00625         struct winbindd_cli_state *state;
00626         socklen_t len;
00627         int sock;
00628         
00629         /* Accept connection */
00630         
00631         len = sizeof(sunaddr);
00632 
00633         do {
00634                 sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
00635         } while (sock == -1 && errno == EINTR);
00636 
00637         if (sock == -1)
00638                 return;
00639         
00640         DEBUG(6,("accepted socket %d\n", sock));
00641         
00642         /* Create new connection structure */
00643         
00644         if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL) {
00645                 close(sock);
00646                 return;
00647         }
00648         
00649         state->sock = sock;
00650 
00651         state->last_access = time(NULL);        
00652 
00653         state->privileged = privileged;
00654 
00655         state->fd_event.fd = state->sock;
00656         state->fd_event.flags = 0;
00657         add_fd_event(&state->fd_event);
00658 
00659         setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
00660                          request_len_recv, state);
00661 
00662         /* Add to connection list */
00663         
00664         winbindd_add_client(state);
00665 }
00666 
00667 /* Remove a client connection from client connection list */
00668 
00669 static void remove_client(struct winbindd_cli_state *state)
00670 {
00671         /* It's a dead client - hold a funeral */
00672         
00673         if (state == NULL) {
00674                 return;
00675         }
00676                 
00677         /* Close socket */
00678                 
00679         close(state->sock);
00680                 
00681         /* Free any getent state */
00682                 
00683         free_getent_state(state->getpwent_state);
00684         free_getent_state(state->getgrent_state);
00685                 
00686         /* We may have some extra data that was not freed if the client was
00687            killed unexpectedly */
00688 
00689         SAFE_FREE(state->response.extra_data.data);
00690 
00691         if (state->mem_ctx != NULL) {
00692                 talloc_destroy(state->mem_ctx);
00693                 state->mem_ctx = NULL;
00694         }
00695 
00696         remove_fd_event(&state->fd_event);
00697                 
00698         /* Remove from list and free */
00699                 
00700         winbindd_remove_client(state);
00701         TALLOC_FREE(state);
00702 }
00703 
00704 /* Shutdown client connection which has been idle for the longest time */
00705 
00706 static BOOL remove_idle_client(void)
00707 {
00708         struct winbindd_cli_state *state, *remove_state = NULL;
00709         time_t last_access = 0;
00710         int nidle = 0;
00711 
00712         for (state = winbindd_client_list(); state; state = state->next) {
00713                 if (state->response.result != WINBINDD_PENDING &&
00714                     !state->getpwent_state && !state->getgrent_state) {
00715                         nidle++;
00716                         if (!last_access || state->last_access < last_access) {
00717                                 last_access = state->last_access;
00718                                 remove_state = state;
00719                         }
00720                 }
00721         }
00722 
00723         if (remove_state) {
00724                 DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n",
00725                         nidle, remove_state->sock, (unsigned int)remove_state->pid));
00726                 remove_client(remove_state);
00727                 return True;
00728         }
00729 
00730         return False;
00731 }
00732 
00733 /* check if HUP has been received and reload files */
00734 void winbind_check_sighup(const char *logfile)
00735 {
00736         if (do_sighup) {
00737 
00738                 DEBUG(3, ("got SIGHUP\n"));
00739 
00740                 msg_reload_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), NULL, 0, logfile);
00741                 do_sighup = False;
00742         }
00743 }
00744 
00745 /* check if TERM has been received */
00746 void winbind_check_sigterm(bool in_parent)
00747 {
00748         if (do_sigterm)
00749                 terminate(in_parent);
00750 }
00751 
00752 /* Process incoming clients on listen_sock.  We use a tricky non-blocking,
00753    non-forking, non-threaded model which allows us to handle many
00754    simultaneous connections while remaining impervious to many denial of
00755    service attacks. */
00756 
00757 static void process_loop(void)
00758 {
00759         struct winbindd_cli_state *state;
00760         struct fd_event *ev;
00761         fd_set r_fds, w_fds;
00762         int maxfd, listen_sock, listen_priv_sock, selret;
00763         struct timeval timeout, ev_timeout;
00764 
00765         /* Open Sockets here to get stuff going ASAP */
00766         listen_sock = open_winbindd_socket();
00767         listen_priv_sock = open_winbindd_priv_socket();
00768 
00769         if (listen_sock == -1 || listen_priv_sock == -1) {
00770                 perror("open_winbind_socket");
00771                 exit(1);
00772         }
00773 
00774         /* We'll be doing this a lot */
00775 
00776         /* Handle messages */
00777 
00778         message_dispatch();
00779 
00780         run_events(winbind_event_context(), 0, NULL, NULL);
00781 
00782         /* refresh the trusted domain cache */
00783 
00784         rescan_trusted_domains();
00785 
00786         /* Free up temporary memory */
00787 
00788         lp_TALLOC_FREE();
00789         main_loop_TALLOC_FREE();
00790 
00791         /* Initialise fd lists for select() */
00792 
00793         maxfd = MAX(listen_sock, listen_priv_sock);
00794 
00795         FD_ZERO(&r_fds);
00796         FD_ZERO(&w_fds);
00797         FD_SET(listen_sock, &r_fds);
00798         FD_SET(listen_priv_sock, &r_fds);
00799 
00800         timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
00801         timeout.tv_usec = 0;
00802 
00803         /* Check for any event timeouts. */
00804         if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) {
00805                 timeout = timeval_min(&timeout, &ev_timeout);
00806         }
00807 
00808         /* Set up client readers and writers */
00809 
00810         state = winbindd_client_list();
00811 
00812         while (state) {
00813 
00814                 struct winbindd_cli_state *next = state->next;
00815 
00816                 /* Dispose of client connection if it is marked as 
00817                    finished */ 
00818 
00819                 if (state->finished)
00820                         remove_client(state);
00821 
00822                 state = next;
00823         }
00824 
00825         for (ev = fd_events; ev; ev = ev->next) {
00826                 if (ev->flags & EVENT_FD_READ) {
00827                         FD_SET(ev->fd, &r_fds);
00828                         maxfd = MAX(ev->fd, maxfd);
00829                 }
00830                 if (ev->flags & EVENT_FD_WRITE) {
00831                         FD_SET(ev->fd, &w_fds);
00832                         maxfd = MAX(ev->fd, maxfd);
00833                 }
00834         }
00835 
00836         /* Call select */
00837         
00838         selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
00839 
00840         if (selret == 0) {
00841                 goto no_fds_ready;
00842         }
00843 
00844         if (selret == -1) {
00845                 if (errno == EINTR) {
00846                         goto no_fds_ready;
00847                 }
00848 
00849                 /* Select error, something is badly wrong */
00850 
00851                 perror("select");
00852                 exit(1);
00853         }
00854 
00855         /* selret > 0 */
00856 
00857         ev = fd_events;
00858         while (ev != NULL) {
00859                 struct fd_event *next = ev->next;
00860                 int flags = 0;
00861                 if (FD_ISSET(ev->fd, &r_fds))
00862                         flags |= EVENT_FD_READ;
00863                 if (FD_ISSET(ev->fd, &w_fds))
00864                         flags |= EVENT_FD_WRITE;
00865                 if (flags)
00866                         ev->handler(ev, flags);
00867                 ev = next;
00868         }
00869 
00870         if (FD_ISSET(listen_sock, &r_fds)) {
00871                 while (winbindd_num_clients() >
00872                        WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
00873                         DEBUG(5,("winbindd: Exceeding %d client "
00874                                  "connections, removing idle "
00875                                  "connection.\n",
00876                                  WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
00877                         if (!remove_idle_client()) {
00878                                 DEBUG(0,("winbindd: Exceeding %d "
00879                                          "client connections, no idle "
00880                                          "connection found\n",
00881                                          WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
00882                                 break;
00883                         }
00884                 }
00885                 /* new, non-privileged connection */
00886                 new_connection(listen_sock, False);
00887         }
00888             
00889         if (FD_ISSET(listen_priv_sock, &r_fds)) {
00890                 while (winbindd_num_clients() >
00891                        WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
00892                         DEBUG(5,("winbindd: Exceeding %d client "
00893                                  "connections, removing idle "
00894                                  "connection.\n",
00895                                  WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
00896                         if (!remove_idle_client()) {
00897                                 DEBUG(0,("winbindd: Exceeding %d "
00898                                          "client connections, no idle "
00899                                          "connection found\n",
00900                                          WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
00901                                 break;
00902                         }
00903                 }
00904                 /* new, privileged connection */
00905                 new_connection(listen_priv_sock, True);
00906         }
00907 
00908  no_fds_ready:
00909 
00910 #if 0
00911         winbindd_check_cache_size(time(NULL));
00912 #endif
00913 
00914         /* Check signal handling things */
00915 
00916         winbind_check_sigterm(true);
00917         winbind_check_sighup(NULL);
00918 
00919         if (do_sigusr2) {
00920                 print_winbindd_status();
00921                 do_sigusr2 = False;
00922         }
00923 
00924         if (do_sigchld) {
00925                 pid_t pid;
00926 
00927                 do_sigchld = False;
00928 
00929                 while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
00930                         winbind_child_died(pid);
00931                 }
00932         }
00933 }
00934 
00935 /* Main function */
00936 
00937 int main(int argc, char **argv, char **envp)
00938 {
00939         pstring logfile;
00940         static BOOL Fork = True;
00941         static BOOL log_stdout = False;
00942         static BOOL no_process_group = False;
00943         struct poptOption long_options[] = {
00944                 POPT_AUTOHELP
00945                 { "stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" },
00946                 { "foreground", 'F', POPT_ARG_VAL, &Fork, False, "Daemon in foreground mode" },
00947                 { "no-process-group", 0, POPT_ARG_VAL, &no_process_group, True, "Don't create a new process group" },
00948                 { "interactive", 'i', POPT_ARG_NONE, NULL, 'i', "Interactive mode" },
00949                 { "no-caching", 'n', POPT_ARG_VAL, &opt_nocache, True, "Disable caching" },
00950                 POPT_COMMON_SAMBA
00951                 POPT_TABLEEND
00952         };
00953         poptContext pc;
00954         int opt;
00955 
00956         /* glibc (?) likes to print "User defined signal 1" and exit if a
00957            SIGUSR[12] is received before a handler is installed */
00958 
00959         CatchSignal(SIGUSR1, SIG_IGN);
00960         CatchSignal(SIGUSR2, SIG_IGN);
00961 
00962         fault_setup((void (*)(void *))fault_quit );
00963         dump_core_setup("winbindd");
00964 
00965         load_case_tables();
00966 
00967         /* Initialise for running in non-root mode */
00968 
00969         sec_init();
00970 
00971         set_remote_machine_name("winbindd", False);
00972 
00973         /* Set environment variable so we don't recursively call ourselves.
00974            This may also be useful interactively. */
00975 
00976         if ( !winbind_off() ) {
00977                 DEBUG(0,("Failed to disable recusive winbindd calls.  Exiting.\n"));
00978                 exit(1);
00979         }
00980 
00981         /* Initialise samba/rpc client stuff */
00982 
00983         pc = poptGetContext("winbindd", argc, (const char **)argv, long_options,
00984                                                 POPT_CONTEXT_KEEP_FIRST);
00985 
00986         while ((opt = poptGetNextOpt(pc)) != -1) {
00987                 switch (opt) {
00988                         /* Don't become a daemon */
00989                 case 'i':
00990                         interactive = True;
00991                         log_stdout = True;
00992                         Fork = False;
00993                         break;
00994                 }
00995         }
00996 
00997 
00998         if (log_stdout && Fork) {
00999                 printf("Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i)\n");
01000                 poptPrintUsage(pc, stderr, 0);
01001                 exit(1);
01002         }
01003 
01004         if (!override_logfile) {
01005                 pstr_sprintf(logfile, "%s/winbindd.log", dyn_LOGFILEBASE);
01006                 lp_set_logfile(logfile);
01007         }
01008         setup_logging("winbindd", log_stdout);
01009         reopen_logs();
01010 
01011         DEBUG(1, ("winbindd version %s started.\n%s\n", 
01012                   SAMBA_VERSION_STRING, 
01013                   COPYRIGHT_STARTUP_MESSAGE) );
01014 
01015         if (!reload_services_file(NULL)) {
01016                 DEBUG(0, ("error opening config file\n"));
01017                 exit(1);
01018         }
01019 
01020         if (!directory_exist(lp_lockdir(), NULL)) {
01021                 mkdir(lp_lockdir(), 0755);
01022         }
01023 
01024         /* Setup names. */
01025 
01026         if (!init_names())
01027                 exit(1);
01028 
01029         load_interfaces();
01030 
01031         if (!secrets_init()) {
01032 
01033                 DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n"));
01034                 return False;
01035         }
01036 
01037         /* Enable netbios namecache */
01038 
01039         namecache_enable();
01040 
01041         /* Winbind daemon initialisation */
01042 
01043         if ( ! NT_STATUS_IS_OK(idmap_init_cache()) ) {
01044                 DEBUG(1, ("Could not init idmap cache!\n"));            
01045         }
01046 
01047         /* Unblock all signals we are interested in as they may have been
01048            blocked by the parent process. */
01049 
01050         BlockSignals(False, SIGINT);
01051         BlockSignals(False, SIGQUIT);
01052         BlockSignals(False, SIGTERM);
01053         BlockSignals(False, SIGUSR1);
01054         BlockSignals(False, SIGUSR2);
01055         BlockSignals(False, SIGHUP);
01056         BlockSignals(False, SIGCHLD);
01057 
01058         /* Setup signal handlers */
01059         
01060         CatchSignal(SIGINT, termination_handler);      /* Exit on these sigs */
01061         CatchSignal(SIGQUIT, termination_handler);
01062         CatchSignal(SIGTERM, termination_handler);
01063         CatchSignal(SIGCHLD, sigchld_handler);
01064 
01065         CatchSignal(SIGPIPE, SIG_IGN);                 /* Ignore sigpipe */
01066 
01067         CatchSignal(SIGUSR2, sigusr2_handler);         /* Debugging sigs */
01068         CatchSignal(SIGHUP, sighup_handler);
01069 
01070         if (!interactive)
01071                 become_daemon(Fork, no_process_group);
01072 
01073         pidfile_create("winbindd");
01074 
01075 #if HAVE_SETPGID
01076         /*
01077          * If we're interactive we want to set our own process group for
01078          * signal management.
01079          */
01080         if (interactive && !no_process_group)
01081                 setpgid( (pid_t)0, (pid_t)0);
01082 #endif
01083 
01084         TimeInit();
01085 
01086         /* Initialise messaging system */
01087 
01088         if (!message_init()) {
01089                 DEBUG(0, ("unable to initialize messaging system\n"));
01090                 exit(1);
01091         }
01092         
01093         /* Initialize cache (ensure version is correct). */
01094         if (!initialize_winbindd_cache()) {
01095                 exit(1);
01096         }
01097 
01098         /* React on 'smbcontrol winbindd reload-config' in the same way
01099            as to SIGHUP signal */
01100         message_register(MSG_SMB_CONF_UPDATED, msg_reload_services, NULL);
01101         message_register(MSG_SHUTDOWN, msg_shutdown, NULL);
01102 
01103         /* Handle online/offline messages. */
01104         message_register(MSG_WINBIND_OFFLINE, winbind_msg_offline, NULL);
01105         message_register(MSG_WINBIND_ONLINE, winbind_msg_online, NULL);
01106         message_register(MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus,
01107                          NULL);
01108 
01109         poptFreeContext(pc);
01110 
01111         netsamlogon_cache_init(); /* Non-critical */
01112         
01113         if (!init_domain_list()) {
01114                 DEBUG(0,("unable to initalize domain list\n"));
01115                 exit(1);
01116         }
01117 
01118         init_idmap_child();
01119 
01120         smb_nscd_flush_user_cache();
01121         smb_nscd_flush_group_cache();
01122 
01123         /* Loop waiting for requests */
01124 
01125         while (1)
01126                 process_loop();
01127 
01128         return 0;
01129 }

Sambaに対してSat Aug 29 21:23:09 2009に生成されました。  doxygen 1.4.7