📄 amandad.c
字号:
state_machine(as, A_RECVREP, NULL);}/* * Called when a repfd has timed out */static voidtimeout_repfd( void * cookie){ struct active_service *as = cookie; assert(as != NULL); assert(as->ev_reptimeout != NULL); state_machine(as, A_TIMEOUT, NULL);}/* * Called when a handle has received data */static voidprotocol_recv( void * cookie, pkt_t * pkt, security_status_t status){ struct active_service *as = cookie; assert(as != NULL); switch (status) { case S_OK: dbprintf(_("received %s pkt:\n<<<<<\n%s>>>>>\n"), pkt_type2str(pkt->type), pkt->body); state_machine(as, A_RECVPKT, pkt); break; case S_TIMEOUT: dbprintf(_("timeout\n")); state_machine(as, A_TIMEOUT, NULL); break; case S_ERROR: dbprintf(_("receive error: %s\n"), security_geterror(as->security_handle)); break; }}/* * This is a generic relay function that just reads data from one of * the process's pipes and passes it up the equivalent security_stream_t */static voidprocess_readnetfd( void * cookie){ pkt_t nak; struct datafd_handle *dh = cookie; struct active_service *as = dh->as; ssize_t n; nak.body = NULL; do { n = read(dh->fd_read, as->databuf, SIZEOF(as->databuf)); } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); /* * Process has died. */ if (n < 0) { pkt_init(&nak, P_NAK, _("A ERROR data descriptor %d broken: %s\n"), dh->fd_read, strerror(errno)); goto sendnak; } /* * Process has closed the pipe. Just remove this event handler. * If all pipes are closed, shut down this service. */ if (n == 0) { event_release(dh->ev_read); dh->ev_read = NULL; if(dh->ev_write == NULL) { security_stream_close(dh->netfd); dh->netfd = NULL; } for (dh = &as->data[0]; dh < &as->data[DATA_FD_COUNT]; dh++) { if (dh->netfd != NULL) return; } service_delete(as); return; } if (security_stream_write(dh->netfd, as->databuf, (size_t)n) < 0) { /* stream has croaked */ pkt_init(&nak, P_NAK, _("ERROR write error on stream %d: %s\n"), security_stream_id(dh->netfd), security_stream_geterror(dh->netfd)); goto sendnak; } return;sendnak: do_sendpkt(as->security_handle, &nak); service_delete(as); amfree(nak.body);}/* * This is a generic relay function that just read data from one of * the security_stream_t and passes it up the equivalent process's pipes */static voidprocess_writenetfd( void * cookie, void * buf, ssize_t size){ struct datafd_handle *dh; assert(cookie != NULL); dh = cookie; if (dh->fd_write <= 0) { dbprintf(_("process_writenetfd: dh->fd_write <= 0\n")); } else if (size > 0) { fullwrite(dh->fd_write, buf, (size_t)size); security_stream_read(dh->netfd, process_writenetfd, dh); } else { aclose(dh->fd_write); }}/* * Convert a local stream handle (DATA_FD...) into something that * can be sent to the amanda server. * * Returns a number that should be sent to the server in the REP packet. */static intallocstream( struct active_service * as, int handle){ struct datafd_handle *dh; /* if the handle is -1, then we don't bother */ if (handle < 0) return (-1); /* make sure the handle's kosher */ if (handle < DATA_FD_OFFSET || handle >= DATA_FD_OFFSET + DATA_FD_COUNT) return (-1); /* get a pointer into our handle array */ dh = &as->data[handle - DATA_FD_OFFSET]; /* make sure we're not already using the net handle */ if (dh->netfd != NULL) return (-1); /* allocate a stream from the security layer and return */ dh->netfd = security_stream_server(as->security_handle); if (dh->netfd == NULL) { dbprintf(_("couldn't open stream to server: %s\n"), security_geterror(as->security_handle)); return (-1); } /* * convert the stream into a numeric id that can be sent to the * remote end. */ return (security_stream_id(dh->netfd));}/* * Create a new service instance */static struct active_service *service_new( security_handle_t * security_handle, const char * cmd, const char * arguments){ int i; int data_read[DATA_FD_COUNT + 1][2]; int data_write[DATA_FD_COUNT + 1][2]; struct active_service *as; pid_t pid; int newfd; assert(security_handle != NULL); assert(cmd != NULL); assert(arguments != NULL); /* a plethora of pipes */ for (i = 0; i < DATA_FD_COUNT + 1; i++) { if (pipe(data_read[i]) < 0) { error(_("pipe: %s\n"), strerror(errno)); /*NOTREACHED*/ } if (pipe(data_write[i]) < 0) { error(_("pipe: %s\n"), strerror(errno)); /*NOTREACHED*/ } } switch(pid = fork()) { case -1: error(_("could not fork service %s: %s\n"), cmd, strerror(errno)); /*NOTREACHED*/ default: /* * The parent. Close the far ends of our pipes and return. */ as = alloc(SIZEOF(*as)); as->cmd = stralloc(cmd); as->arguments = stralloc(arguments); as->security_handle = security_handle; as->state = NULL; as->pid = pid; as->send_partial_reply = 0; if(strcmp(cmd+(strlen(cmd)-8), "sendsize") == 0) { g_option_t *g_options; char *option_str, *p; option_str = stralloc(as->arguments+8); p = strchr(option_str,'\n'); if(p) *p = '\0'; g_options = parse_g_options(option_str, 1); if(am_has_feature(g_options->features, fe_partial_estimate)) { as->send_partial_reply = 1; } free_g_options(g_options); amfree(option_str); } /* write to the request pipe */ aclose(data_read[0][0]); as->reqfd = data_read[0][1]; /* * read from the reply pipe */ as->repfd = data_write[0][0]; aclose(data_write[0][1]); as->ev_repfd = NULL; as->repbuf = NULL; as->repbufsize = 0; as->bufsize = 0; as->repretry = 0; as->rep_pkt.body = NULL; /* * read from the rest of the general-use pipes * (netfds are opened as the client requests them) */ for (i = 0; i < DATA_FD_COUNT; i++) { aclose(data_read[i + 1][1]); aclose(data_write[i + 1][0]); as->data[i].fd_read = data_read[i + 1][0]; as->data[i].fd_write = data_write[i + 1][1]; as->data[i].ev_read = NULL; as->data[i].ev_write = NULL; as->data[i].netfd = NULL; as->data[i].as = as; } /* add it to the service queue */ /* increment the active service count */ TAILQ_INSERT_TAIL(&serviceq.tailq, as, tq); serviceq.qlength++; return (as); case 0: /* * The child. Put our pipes in their advertised locations * and start up. */ /* * The data stream is stdin in the new process */ if (dup2(data_read[0][0], 0) < 0) { error(_("dup %d to %d failed: %s\n"), data_read[0][0], 0, strerror(errno)); /*NOTREACHED*/ } aclose(data_read[0][0]); aclose(data_read[0][1]); /* * The reply stream is stdout */ if (dup2(data_write[0][1], 1) < 0) { error(_("dup %d to %d failed: %s\n"), data_write[0][1], 1, strerror(errno)); } aclose(data_write[0][0]); aclose(data_write[0][1]); for (i = 0; i < DATA_FD_COUNT; i++) { aclose(data_read[i + 1][0]); aclose(data_write[i + 1][1]); } /* * Make sure they are not open in the range DATA_FD_OFFSET to * DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1 */ for (i = 0; i < DATA_FD_COUNT; i++) { while(data_read[i + 1][1] >= DATA_FD_OFFSET && data_read[i + 1][1] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) { newfd = dup(data_read[i + 1][1]); if(newfd == -1) error(_("Can't dup out off DATA_FD range")); data_read[i + 1][1] = newfd; } while(data_write[i + 1][0] >= DATA_FD_OFFSET && data_write[i + 1][0] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) { newfd = dup(data_write[i + 1][0]); if(newfd == -1) error(_("Can't dup out off DATA_FD range")); data_write[i + 1][0] = newfd; } } for (i = 0; i < DATA_FD_COUNT*2; i++) close(DATA_FD_OFFSET + i); /* * The rest start at the offset defined in amandad.h, and continue * through the internal defined. */ for (i = 0; i < DATA_FD_COUNT; i++) { if (dup2(data_read[i + 1][1], i*2 + DATA_FD_OFFSET) < 0) { error(_("dup %d to %d failed: %s\n"), data_read[i + 1][1], i + DATA_FD_OFFSET, strerror(errno)); } aclose(data_read[i + 1][1]); if (dup2(data_write[i + 1][0], i*2 + 1 + DATA_FD_OFFSET) < 0) { error(_("dup %d to %d failed: %s\n"), data_write[i + 1][0], i + DATA_FD_OFFSET, strerror(errno)); } aclose(data_write[i + 1][0]); } /* close all unneeded fd */ close(STDERR_FILENO); debug_dup_stderr_to_debug(); safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2); execle(cmd, cmd, "amandad", auth, (char *)NULL, safe_env()); error(_("could not exec service %s: %s\n"), cmd, strerror(errno)); /*NOTREACHED*/ } return NULL;}/* * Unallocate a service instance */static voidservice_delete( struct active_service * as){ int i; struct datafd_handle *dh; amandad_debug(1, _("closing service: %s\n"), (as->cmd)?as->cmd:_("??UNKONWN??")); assert(as != NULL); assert(as->cmd != NULL); amfree(as->cmd); assert(as->arguments != NULL); amfree(as->arguments); if (as->reqfd != -1) aclose(as->reqfd); if (as->repfd != -1) aclose(as->repfd); if (as->ev_repfd != NULL) event_release(as->ev_repfd); if (as->ev_reptimeout != NULL) event_release(as->ev_reptimeout); for (i = 0; i < DATA_FD_COUNT; i++) { dh = &as->data[i]; aclose(dh->fd_read); aclose(dh->fd_write); if (dh->netfd != NULL) security_stream_close(dh->netfd); if (dh->ev_read != NULL) event_release(dh->ev_read); if (dh->ev_write != NULL) event_release(dh->ev_write); } if (as->security_handle != NULL) security_close(as->security_handle); assert(as->pid > 0); kill(as->pid, SIGTERM); waitpid(as->pid, NULL, WNOHANG); TAILQ_REMOVE(&serviceq.tailq, as, tq); assert(serviceq.qlength > 0); serviceq.qlength--; amfree(as->cmd); amfree(as->arguments); amfree(as->repbuf); amfree(as->rep_pkt.body); amfree(as); if(exit_on_qlength == 0 && serviceq.qlength == 0) { dbclose(); exit(0); }}/* * Like 'fullwrite', but does the work in a child process so pipelines * do not hang. */static intwritebuf( struct active_service * as, const void * bufp, size_t size){ pid_t pid; ssize_t writesize; switch (pid=fork()) { case -1: break; default: waitpid(pid, NULL, WNOHANG); return 0; /* this is the parent */ case 0: /* this is the child */ close(as->repfd); writesize = fullwrite(as->reqfd, bufp, size); exit(writesize != (ssize_t)size); /* NOTREACHED */ } return -1;}static ssize_tdo_sendpkt( security_handle_t * handle, pkt_t * pkt){ dbprintf(_("sending %s pkt:\n<<<<<\n%s>>>>>\n"), pkt_type2str(pkt->type), pkt->body); if (handle) return security_sendpkt(handle, pkt); else return 1;}/* * Convert a state into a string */static const char *state2str( state_t state){ static const struct { state_t state; const char str[13]; } states[] = {#define X(state) { state, stringize(state) } X(s_sendack), X(s_repwait), X(s_processrep), X(s_sendrep), X(s_ackwait),#undef X }; int i; for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++) if (state == states[i].state) return (states[i].str); return (_("INVALID STATE"));}/* * Convert an action into a string */static const char *action2str( action_t action){ static const struct { action_t action; const char str[12]; } actions[] = {#define X(action) { action, stringize(action) } X(A_START), X(A_RECVPKT), X(A_RECVREP), X(A_PENDING), X(A_FINISH), X(A_CONTINUE), X(A_SENDNAK), X(A_TIMEOUT),#undef X }; int i; for (i = 0; i < (int)(sizeof(actions) / sizeof(actions[0])); i++) if (action == actions[i].action) return (actions[i].str); return (_("UNKNOWN ACTION"));}static char *amandad_get_security_conf( char * string, void * arg){ (void)arg; /* Quiet unused parameter warning */ if (!string || !*string) return(NULL); if (strcmp(string, "kencrypt")==0) { if (amandad_kencrypt == KENCRYPT_YES) return ("yes"); else return (NULL); } return(NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -