📄 security-util.c
字号:
pkt_t pkt; struct sec_handle *rh = cookie; assert(rh != NULL); auth_debug(1, _("sec: recvpkt_callback: %zd\n"), bufsize); /* * We need to cancel the recvpkt request before calling * the callback because the callback may reschedule us. */ stream_recvpkt_cancel(rh); switch (bufsize) { case 0: security_seterror(&rh->sech, _("EOF on read from %s"), rh->hostname); (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR); return; case -1: security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr)); (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR); return; default: break; } parse_pkt(&pkt, buf, (size_t)bufsize); auth_debug(1, _("sec: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n"), pkt_type2str(pkt.type), pkt.type, rh->hostname, pkt.body); if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0) (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR); else (*rh->fn.recvpkt)(rh->arg, &pkt, S_OK); amfree(pkt.body);}/* * Callback for tcpm_stream_read_sync */static voidstream_read_sync_callback( void * s){ struct sec_stream *rs = s; assert(rs != NULL); auth_debug(1, _("sec: stream_read_callback_sync: handle %d\n"), rs->handle); /* * Make sure this was for us. If it was, then blow away the handle * so it doesn't get claimed twice. Otherwise, leave it alone. * * If the handle is EOF, pass that up to our callback. */ if (rs->rc->handle == rs->handle) { auth_debug(1, _("sec: stream_read_callback_sync: it was for us\n")); rs->rc->handle = H_TAKEN; } else if (rs->rc->handle != H_EOF) { auth_debug(1, _("sec: stream_read_callback_sync: not for us\n")); return; } /* * Remove the event first, and then call the callback. * We remove it first because we don't want to get in their * way if they reschedule it. */ tcpm_stream_read_cancel(rs); if (rs->rc->pktlen <= 0) { auth_debug(1, _("sec: stream_read_sync_callback: %s\n"), rs->rc->errmsg); security_stream_seterror(&rs->secstr, rs->rc->errmsg); if(rs->closed_by_me == 0 && rs->closed_by_network == 0) sec_tcp_conn_put(rs->rc); rs->closed_by_network = 1; return; } auth_debug(1, _("sec: stream_read_callback_sync: read %zd bytes from %s:%d\n"), rs->rc->pktlen, rs->rc->hostname, rs->handle);}/* * Callback for tcpm_stream_read */static voidstream_read_callback( void * arg){ struct sec_stream *rs = arg; assert(rs != NULL); auth_debug(1, _("sec: stream_read_callback: handle %d\n"), rs->handle); /* * Make sure this was for us. If it was, then blow away the handle * so it doesn't get claimed twice. Otherwise, leave it alone. * * If the handle is EOF, pass that up to our callback. */ if (rs->rc->handle == rs->handle) { auth_debug(1, _("sec: stream_read_callback: it was for us\n")); rs->rc->handle = H_TAKEN; } else if (rs->rc->handle != H_EOF) { auth_debug(1, _("sec: stream_read_callback: not for us\n")); return; } /* * Remove the event first, and then call the callback. * We remove it first because we don't want to get in their * way if they reschedule it. */ tcpm_stream_read_cancel(rs); if (rs->rc->pktlen <= 0) { auth_debug(1, _("sec: stream_read_callback: %s\n"), rs->rc->errmsg); security_stream_seterror(&rs->secstr, rs->rc->errmsg); if(rs->closed_by_me == 0 && rs->closed_by_network == 0) sec_tcp_conn_put(rs->rc); rs->closed_by_network = 1; (*rs->fn)(rs->arg, NULL, rs->rc->pktlen); return; } auth_debug(1, _("sec: stream_read_callback: read %zd bytes from %s:%d\n"), rs->rc->pktlen, rs->rc->hostname, rs->handle); (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen); auth_debug(1, _("sec: after callback stream_read_callback\n"));}/* * The callback for the netfd for the event handler * Determines if this packet is for this security handle, * and does the real callback if so. */static voidsec_tcp_conn_read_callback( void * cookie){ struct tcp_conn * rc = cookie; struct sec_handle * rh; pkt_t pkt; ssize_t rval; int revent; assert(cookie != NULL); auth_debug(1, _("sec: conn_read_callback\n")); /* Read the data off the wire. If we get errors, shut down. */ rval = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, &rc->pkt, &rc->pktlen, 60); auth_debug(1, _("sec: conn_read_callback: tcpm_recv_token returned %zd\n"), rval); if (rval < 0 || rc->handle == H_EOF) { rc->pktlen = rval; rc->handle = H_EOF; revent = event_wakeup((event_id_t)rc); auth_debug(1, _("sec: conn_read_callback: event_wakeup return %d\n"), revent); /* delete our 'accept' reference */ if (rc->accept_fn != NULL) { if(rc->refcnt != 1) { dbprintf(_("STRANGE, rc->refcnt should be 1, it is %d\n"), rc->refcnt); rc->refcnt=1; } rc->accept_fn = NULL; sec_tcp_conn_put(rc); } return; } if(rval == 0) { rc->pktlen = 0; revent = event_wakeup((event_id_t)rc); auth_debug(1, _("sec: conn_read_callback: event_wakeup return %d\n"), revent); return; } /* If there are events waiting on this handle, we're done */ rc->donotclose = 1; revent = event_wakeup((event_id_t)rc); auth_debug(1, _("sec: conn_read_callback: event_wakeup return %zd\n"), rval); rc->donotclose = 0; if (rc->handle == H_TAKEN || rc->pktlen == 0) { if(rc->refcnt == 0) amfree(rc); return; } assert(rc->refcnt > 0); /* If there is no accept fn registered, then drop the packet */ if (rc->accept_fn == NULL) return; rh = alloc(SIZEOF(*rh)); security_handleinit(&rh->sech, rc->driver); rh->hostname = stralloc(rc->hostname); rh->ev_timeout = NULL; rh->rc = rc; rh->peer = rc->peer; rh->rs = tcpma_stream_client(rh, rc->handle); auth_debug(1, _("sec: new connection\n")); pkt.body = NULL; parse_pkt(&pkt, rc->pkt, (size_t)rc->pktlen); auth_debug(1, _("sec: calling accept_fn\n")); if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0) (*rc->accept_fn)(&rh->sech, NULL); else (*rc->accept_fn)(&rh->sech, &pkt); amfree(pkt.body);}voidparse_pkt( pkt_t * pkt, const void *buf, size_t bufsize){ const unsigned char *bufp = buf; auth_debug(1, _("sec: parse_pkt: parsing buffer of %zu bytes\n"), bufsize); pkt->type = (pktype_t)*bufp++; bufsize--; pkt->packet_size = bufsize+1; pkt->body = alloc(pkt->packet_size); if (bufsize == 0) { pkt->body[0] = '\0'; } else { memcpy(pkt->body, bufp, bufsize); pkt->body[pkt->packet_size - 1] = '\0'; } pkt->size = strlen(pkt->body); auth_debug(1, _("sec: parse_pkt: %s (%d): \"%s\"\n"), pkt_type2str(pkt->type), pkt->type, pkt->body);}/* * Convert a packet header into a string */const char *pkthdr2str( const struct sec_handle * rh, const pkt_t * pkt){ static char retbuf[256]; assert(rh != NULL); assert(pkt != NULL); g_snprintf(retbuf, SIZEOF(retbuf), _("Amanda %d.%d %s HANDLE %s SEQ %d\n"), VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type), rh->proto_handle, rh->sequence); auth_debug(1, _("bsd: pkthdr2str handle '%s'\n"), rh->proto_handle); /* check for truncation. If only we had asprintf()... */ assert(retbuf[strlen(retbuf) - 1] == '\n'); return (retbuf);}/* * Parses out the header line in 'str' into the pkt and handle * Returns negative on parse error. */intstr2pkthdr( udp_handle_t * udp){ char *str; const char *tok; pkt_t *pkt; pkt = &udp->pkt; assert(udp->dgram.cur != NULL); str = stralloc(udp->dgram.cur); /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */ /* Read in "Amanda" */ if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0) goto parse_error; /* nothing is done with the major/minor numbers currently */ if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL) goto parse_error; /* Read in the packet type */ if ((tok = strtok(NULL, " ")) == NULL) goto parse_error; amfree(pkt->body); pkt_init_empty(pkt, pkt_str2type(tok)); if (pkt->type == (pktype_t)-1) goto parse_error; /* Read in "HANDLE" */ if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0) goto parse_error; /* parse the handle */ if ((tok = strtok(NULL, " ")) == NULL) goto parse_error; amfree(udp->handle); udp->handle = stralloc(tok); /* Read in "SEQ" */ if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0) goto parse_error; /* parse the sequence number */ if ((tok = strtok(NULL, "\n")) == NULL) goto parse_error; udp->sequence = atoi(tok); /* Save the body, if any */ if ((tok = strtok(NULL, "")) != NULL) pkt_cat(pkt, "%s", tok); amfree(str); return (0);parse_error:#if 0 /* XXX we have no way of passing this back up */ security_seterror(&rh->sech, "parse error in packet header : '%s'", origstr);#endif amfree(str); return (-1);}char *check_user( struct sec_handle * rh, const char * remoteuser, const char * service){ struct passwd *pwd; char *r; char *result = NULL; char *localuser = NULL; /* lookup our local user name */ if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) { return vstrallocf(_("getpwnam(%s) failed."), CLIENT_LOGIN); } /* * Make a copy of the user name in case getpw* is called by * any of the lower level routines. */ localuser = stralloc(pwd->pw_name);#ifndef USE_AMANDAHOSTS r = check_user_ruserok(rh->hostname, pwd, remoteuser);#else r = check_user_amandahosts(rh->hostname, &rh->peer, pwd, remoteuser, service);#endif if (r != NULL) { result = vstrallocf( _("user %s from %s is not allowed to execute the service %s: %s"), remoteuser, rh->hostname, service, r); amfree(r); } amfree(localuser); return result;}/* * See if a remote user is allowed in. This version uses ruserok() * and friends. * * Returns NULL on success, or error message on error. */char *check_user_ruserok( const char * host, struct passwd * pwd, const char * remoteuser){ int saved_stderr; int fd[2]; FILE *fError; amwait_t exitcode; pid_t ruserok_pid; pid_t pid; char *es; char *result; int ok; uid_t myuid = getuid(); /* * note that some versions of ruserok (eg SunOS 3.2) look in * "./.rhosts" rather than "~CLIENT_LOGIN/.rhosts", so we have to * chdir ourselves. Sigh. * * And, believe it or not, some ruserok()'s try an initgroup just * for the hell of it. Since we probably aren't root at this point * it'll fail, and initgroup "helpfully" will blatt "Setgroups: Not owner" * into our stderr output even though the initgroup failure is not a * problem and is expected. Thanks a lot. Not. */ if (pipe(fd) != 0) { return stralloc2(_("pipe() fails: "), strerror(errno)); } if ((ruserok_pid = fork()) < 0) { return stralloc2(_("fork() fails: "), strerror(errno)); } else if (ruserok_pid == 0) { int ec; close(fd[0]); fError = fdopen(fd[1], "w"); if (!fError) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } /* pamper braindead ruserok's */ if (chdir(pwd->pw_dir) != 0) { g_fprintf(fError, _("chdir(%s) failed: %s"), pwd->pw_dir, strerror(errno)); fclose(fError); exit(1); } if (debug_auth >= 9) { char *dir = stralloc(pwd->pw_dir); auth_debug(9, _("bsd: calling ruserok(%s, %d, %s, %s)\n"), host, ((myuid == 0) ? 1 : 0), remoteuser, pwd->pw_name); if (myuid == 0) { auth_debug(9, _("bsd: because you are running as root, ")); auth_debug(9, _("/etc/hosts.equiv will not be used\n")); } else { show_stat_info("/etc/hosts.equiv", NULL); } show_stat_info(dir, "/.rhosts"); amfree(dir); } saved_stderr = dup(2); close(2); if (open("/dev/null", O_RDWR) == -1) { auth_debug(1, _("Could not open /dev/null: %s\n"), strerror(errno)); ec = 1; } else { ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN); if (ok < 0) { ec = 1; } else { ec = 0; } } (void)dup2(saved_stderr,2); close(saved_stderr); exit(ec); } close(fd[1]); fError = fdopen(fd[0], "r"); if (!fError) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } result = NULL; while ((es = agets(fError)) != NULL) { if (*es == 0) { amfree(es); continue; } if (result == NULL) { result = stralloc(""); } else { strappend(result, ": "); } strappend(result, es); amfree(es); } close(fd[0]); pid = wait(&exitcode); while (pid != ruserok_pid) { if ((pid == (pid_t) -1) && (errno != EINTR)) { amfree(result); return vstrallocf(_("ruserok wait failed: %s"), strerror(errno)); } pid = wait(&exitcode); } if (!WIFEXITED(exitcode) || WEXITSTATUS(exitcode) != 0) { amfree(result); result = str_exit_status("ruserok child", exitcode); } else { amfree(result); } return result;}/* * Check to see if a user is allowed in. This version uses .amandahosts * Returns an error message on failure, or NULL on success. */char *check_user_amandahosts( const char * host, struct sockaddr_storage *addr, struct passwd * pwd, const char * remoteuser, const char * service){ char *line = NULL; char *filehost; const char *fileuser; char *ptmp = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -