X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fsecurity.c;h=603813370eb4cbed9a732008593d85e31ebf27be;hb=HEAD;hp=018e7a26a79a623bae042978f5082ee94eb8c07e;hpb=3ab887b9bc819a846c75dd7f2ee5d41fac22b19f;p=debian%2Famanda diff --git a/common-src/security.c b/common-src/security.c index 018e7a2..6038133 100644 --- a/common-src/security.c +++ b/common-src/security.c @@ -1,6 +1,7 @@ /* * Amanda, The Advanced Maryland Automatic Network Disk Archiver - * Copyright (c) 1991-1998 University of Maryland at College Park + * Copyright (c) 1999 University of Maryland at College Park + * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -24,590 +25,155 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: security.c,v 1.17.2.6.4.1.2.6 2004/04/29 20:47:40 martinea Exp $ + * $Id: security.c,v 1.28 2006/05/25 01:47:12 johnfranks Exp $ * - * wrapper file for kerberos security + * Security driver interface for the Amanda backup system. */ #include "amanda.h" -#include "clock.h" +#include "arglist.h" +#include "packet.h" +#include "security.h" -/* - * Change the following from #undef to #define to cause detailed logging - * of the security steps, e.g. into /tmp/amanda/amandad*debug. - */ -#undef SHOW_SECURITY_DETAIL - -/* - * If we don't have the new-style wait access functions, use our own, - * compatible with old-style BSD systems at least. Note that we don't - * care about the case w_stopval == WSTOPPED since we don't ask to see - * stopped processes, so should never get them from wait. - */ -#ifndef WEXITSTATUS -# define WEXITSTATUS(r) (((union wait *) &(r))->w_retcode) -# define WTERMSIG(r) (((union wait *) &(r))->w_termsig) - -# undef WIFSIGNALED -# define WIFSIGNALED(r) (((union wait *) &(r))->w_termsig != 0) +#ifdef BSD_SECURITY +extern const security_driver_t bsd_security_driver; +#endif +#ifdef KRB5_SECURITY +extern const security_driver_t krb5_security_driver; #endif +#ifdef RSH_SECURITY +extern const security_driver_t rsh_security_driver; +#endif +#ifdef SSH_SECURITY +extern const security_driver_t ssh_security_driver; +#endif +#ifdef BSDTCP_SECURITY +extern const security_driver_t bsdtcp_security_driver; +#endif +#ifdef BSDUDP_SECURITY +extern const security_driver_t bsdudp_security_driver; +#endif +extern const security_driver_t local_security_driver; -#if defined(TEST) /* { */ -#define SHOW_SECURITY_DETAIL -#undef dbprintf -#define dbprintf(p) printf p -#endif /* } */ +static const security_driver_t *drivers[] = { +#ifdef BSD_SECURITY + &bsd_security_driver, +#endif +#ifdef KRB5_SECURITY + &krb5_security_driver, +#endif +#ifdef RSH_SECURITY + &rsh_security_driver, +#endif +#ifdef SSH_SECURITY + &ssh_security_driver, +#endif +#ifdef BSDTCP_SECURITY + &bsdtcp_security_driver, +#endif +#ifdef BSDUDP_SECURITY + &bsdudp_security_driver, +#endif + &local_security_driver, +}; +#define NDRIVERS (size_t)(sizeof(drivers) / sizeof(drivers[0])) -#if defined(SHOW_SECURITY_DETAIL) /* { */ -void show_stat_info(a, b) - char *a, *b; +/* + * Given a name of a security type, returns the driver structure + */ +const security_driver_t * +security_getdriver( + const char * name) { - char *name = vstralloc(a, b, NULL); - struct stat sbuf; - struct passwd *pwptr; - char *owner; - struct group *grptr; - char *group; + size_t i; - if (stat(name, &sbuf) != 0) { - dbprintf(("%s: cannot stat %s: %s\n", - debug_prefix_time(NULL), name, strerror(errno))); - amfree(name); - return; - } - if ((pwptr = getpwuid(sbuf.st_uid)) == NULL) { - owner = alloc(NUM_STR_SIZE); - ap_snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid); - } else { - owner = stralloc(pwptr->pw_name); - } - if ((grptr = getgrgid(sbuf.st_gid)) == NULL) { - group = alloc(NUM_STR_SIZE); - ap_snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid); - } else { - group = stralloc(grptr->gr_name); + assert(name != NULL); + + for (i = 0; i < NDRIVERS; i++) { + if (strcasecmp(name, drivers[i]->name) == 0) { + dbprintf(_("security_getdriver(name=%s) returns %p\n"), + name, drivers[i]); + return (drivers[i]); + } } - dbprintf(("%s: processing file: %s\n", debug_prefix_time(NULL), name)); - dbprintf(("%s: owner=%s group=%s mode=%03o\n", - debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777))); - amfree(name); - amfree(owner); - amfree(group); + dbprintf(_("security_getdriver(name=%s) returns NULL\n"), name); + return (NULL); } -#endif /* } */ - -#ifdef KRB4_SECURITY /* { */ -#include "krb4-security.c" -#endif /* } */ - -int bsd_security_ok P((struct sockaddr_in *addr, - char *str, uint32_t cksum, char **errstr)); -char *get_bsd_security() +/* + * For the drivers: initialize the common part of a security_handle_t + */ +void +security_handleinit( + security_handle_t * handle, + const security_driver_t * driver) { - struct passwd *pwptr; - - if((pwptr = getpwuid(getuid())) == NULL) - error("can't get login name for my uid %ld", (long)getuid()); - return stralloc2("SECURITY USER ", pwptr->pw_name); + dbprintf(_("security_handleinit(handle=%p, driver=%p (%s))\n"), + handle, driver, driver->name); + handle->driver = driver; + handle->error = stralloc(_("unknown protocol error")); } -int security_ok(addr, str, cksum, errstr) -struct sockaddr_in *addr; -char *str; -uint32_t cksum; -char **errstr; +printf_arglist_function1(void security_seterror, security_handle_t *, handle, + const char *, fmt) { -#ifdef KRB4_SECURITY /* { */ - if(krb4_auth) - return krb4_security_ok(addr, str, cksum, errstr); - else -#endif /* } */ - return bsd_security_ok(addr, str, cksum, errstr); + static char buf[1024]; + va_list argp; + + assert(handle->error != NULL); + arglist_start(argp, fmt); + g_vsnprintf(buf, SIZEOF(buf), fmt, argp); + arglist_end(argp); + handle->error = newstralloc(handle->error, buf); + dbprintf(_("security_seterror(handle=%p, driver=%p (%s) error=%s)\n"), + handle, handle->driver, + handle->driver->name, handle->error); } -#ifdef BSD_SECURITY /* { */ - -int bsd_security_ok(addr, str, cksum, errstr) - struct sockaddr_in *addr; - char *str; - uint32_t cksum; - char **errstr; +void +security_close( + security_handle_t * handle) { - char *remotehost = NULL, *remoteuser = NULL, *localuser = NULL; - char *bad_bsd = NULL; - struct hostent *hp; - struct passwd *pwptr; - int myuid, i, j; - char *s, *fp; - int ch; - char number[NUM_STR_SIZE]; -#ifdef USE_AMANDAHOSTS /* { */ - FILE *fPerm; - char *pbuf = NULL; - char *ptmp; - int pbuf_len; - int amandahostsauth = 0; -#else /* } { */ - FILE *fError; - int saved_stderr; - int fd[2]; - amwait_t wait_exitcode; - int exitcode; - pid_t pid, ruserok_pid; -#endif /* } */ - - *errstr = NULL; - - /* what host is making the request? */ - - hp = gethostbyaddr((char *)&addr->sin_addr, (int)sizeof(addr->sin_addr), - AF_INET); - if(hp == NULL) { - /* XXX include remote address in message */ - *errstr = vstralloc("[", - "addr ", inet_ntoa(addr->sin_addr), ": ", - "hostname lookup failed", - "]", NULL); - return 0; - } - remotehost = stralloc(hp->h_name); - - /* Now let's get the hostent for that hostname */ - hp = gethostbyname( remotehost ); - if(hp == NULL) { - /* XXX include remote hostname in message */ - *errstr = vstralloc("[", - "host ", remotehost, ": ", - "hostname lookup failed", - "]", NULL); - amfree(remotehost); - return 0; - } - - /* Verify that the hostnames match -- they should theoretically */ - if( strncasecmp( remotehost, hp->h_name, strlen(remotehost)+1 ) != 0 ) { - *errstr = vstralloc("[", - "hostnames do not match: ", - remotehost, " ", hp->h_name, - "]", NULL); - amfree(remotehost); - return 0; - } - - /* Now let's verify that the ip which gave us this hostname - * is really an ip for this hostname; or is someone trying to - * break in? (THIS IS THE CRUCIAL STEP) - */ - for (i = 0; hp->h_addr_list[i]; i++) { - if (memcmp(hp->h_addr_list[i], - (char *) &addr->sin_addr, sizeof(addr->sin_addr)) == 0) - break; /* name is good, keep it */ - } - - /* If we did not find it, your DNS is messed up or someone is trying - * to pull a fast one on you. :( - */ - - /* Check even the aliases list. Work around for Solaris if dns goes over NIS */ - - if( !hp->h_addr_list[i] ) { - for (j = 0; hp->h_aliases[j] !=0 ; j++) { - if ( strcmp(hp->h_aliases[j],inet_ntoa(addr->sin_addr)) == 0) - break; /* name is good, keep it */ - } - if( !hp->h_aliases[j] ) { - *errstr = vstralloc("[", - "ip address ", inet_ntoa(addr->sin_addr), - " is not in the ip list for ", remotehost, - "]", - NULL); - amfree(remotehost); - return 0; - } - } - - /* next, make sure the remote port is a "reserved" one */ - - if(ntohs(addr->sin_port) >= IPPORT_RESERVED) { - ap_snprintf(number, sizeof(number), "%d", ntohs(addr->sin_port)); - *errstr = vstralloc("[", - "host ", remotehost, ": ", - "port ", number, " not secure", - "]", NULL); - amfree(remotehost); - return 0; - } - - /* extract the remote user name from the message */ - - s = str; - ch = *s++; - - bad_bsd = vstralloc("[", - "host ", remotehost, ": ", - "bad bsd security line", - "]", NULL); - -#define sc "USER " - if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) { - *errstr = bad_bsd; - bad_bsd = NULL; - amfree(remotehost); - return 0; - } - s += sizeof(sc)-1; - ch = s[-1]; -#undef sc - - skip_whitespace(s, ch); - if(ch == '\0') { - *errstr = bad_bsd; - bad_bsd = NULL; - amfree(remotehost); - return 0; - } - fp = s - 1; - skip_non_whitespace(s, ch); - s[-1] = '\0'; - remoteuser = stralloc(fp); - s[-1] = ch; - amfree(bad_bsd); - - /* lookup our local user name */ - - myuid = getuid(); - if((pwptr = getpwuid(myuid)) == NULL) { - error("error [getpwuid(%d) fails]", myuid); - } - - localuser = stralloc(pwptr->pw_name); - - dbprintf(("%s: bsd security: remote host %s user %s local user %s\n", - debug_prefix_time(NULL), remotehost, remoteuser, localuser)); - -#ifndef USE_AMANDAHOSTS /* { */ - /* - * Note that some versions of ruserok (eg SunOS 3.2) look in - * "./.rhosts" rather than "~localuser/.rhosts", so we have to - * change directories 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) { - error("error [pipe() fails]"); - } - if ((ruserok_pid = fork ()) < 0) { - error("error [fork() fails]"); - } else if (ruserok_pid == 0) { - close(fd[0]); - fError = fdopen(fd[1], "w"); - /* pamper braindead ruserok's */ - if(chdir(pwptr->pw_dir) != 0) { - fprintf(fError, "[chdir(%s) failed: %s]", - pwptr->pw_dir, strerror(errno)); - fclose(fError); - exit(1); - } - -#if defined(SHOW_SECURITY_DETAIL) /* { */ - { - char *dir = stralloc(pwptr->pw_dir); - - dbprintf(("%s: calling ruserok(%s, %d, %s, %s)\n", - debug_prefix_time(NULL), - remotehost, myuid == 0, remoteuser, localuser)); - if (myuid == 0) { - dbprintf(("%s: because you are running as root, ", - debug_prefix(NULL))); - dbprintf(("/etc/hosts.equiv will not be used\n")); - } else { - show_stat_info("/etc/hosts.equiv", NULL); - } - show_stat_info(dir, "/.rhosts"); - amfree(dir); - } -#endif /* } */ - - saved_stderr = dup(2); - close(2); - (void)open("/dev/null", 2); - - if(ruserok(remotehost, myuid == 0, remoteuser, localuser) == -1) { - dup2(saved_stderr,2); - close(saved_stderr); - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] ruserok failed", - NULL); - fputs(*errstr, fError); - fputc('\n', fError); - fclose(fError); - dbprintf(("%s: check failed: %s\n", - debug_prefix_time(NULL), *errstr)); - amfree(*errstr); - exit(1); - } - - dup2(saved_stderr,2); - close(saved_stderr); - dbprintf(("%s: bsd security check to %s from %s@%s passed\n", - debug_prefix_time(NULL), - localuser, remoteuser, remotehost)); - amfree(remotehost); - amfree(remoteuser); - amfree(remoteuser); - exit(0); - } - close(fd[1]); - fError = fdopen(fd[0], "r"); - - while((pid = wait(&wait_exitcode)) == (pid_t)-1 && errno == EINTR) {} - if (pid == (pid_t)-1) { - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] wait failed: ", - strerror(errno), - NULL); - exitcode = 0; - } else if (pid != ruserok_pid) { - ap_snprintf(number, sizeof(number), "%ld", (long)pid); - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] wait got pid ", - number, - NULL); - exitcode = 0; - } else if (WIFSIGNALED(wait_exitcode)) { - ap_snprintf(number, sizeof(number), "%d", WTERMSIG(wait_exitcode)); - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] got signal ", number, - NULL); - exitcode = 0; - } else { - exitcode = WEXITSTATUS(wait_exitcode); - } - if(exitcode) { - if((*errstr = agets(fError)) == NULL) { - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] could not get result", - NULL); - } - } - fclose(fError); - amfree(remotehost); - amfree(localuser); - amfree(remoteuser); - return *errstr == NULL; -#else /* } { */ -#if defined(SHOW_SECURITY_DETAIL) /* { */ - show_stat_info(pwptr->pw_dir, "/.amandahosts"); -#endif /* } */ - - ptmp = stralloc2(pwptr->pw_dir, "/.amandahosts"); - if((fPerm = fopen(ptmp, "r")) == NULL) { - /* - * Put an explanation in the amandad.debug log that will help a - * system administrator fix the problem, but don't send a clue - * back to the other end to tell them what to fix in order to - * be able to hack our system. - */ - dbprintf(("%s: fopen of %s failed: %s\n", - debug_prefix_time(NULL), ptmp, strerror(errno))); - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] open of ", - ptmp, - " failed", NULL); - amfree(ptmp); - amfree(remotehost); - amfree(localuser); - amfree(remoteuser); - return 0; - } - amfree(ptmp); - - for(; (pbuf = agets(fPerm)) != NULL; free(pbuf)) { -#if defined(SHOW_SECURITY_DETAIL) /* { */ - dbprintf(("%s: processing line: <%s>\n", debug_prefix(NULL), pbuf)); -#endif /* } */ - pbuf_len = strlen(pbuf); - s = pbuf; - ch = *s++; - - /* Find end of remote host */ - skip_non_whitespace(s, ch); - if(s - 1 == pbuf) { - memset(pbuf, '\0', pbuf_len); /* leave no trace */ - continue; /* no remotehost field */ - } - s[-1] = '\0'; /* terminate remotehost field */ - - /* Find start of remote user */ - skip_whitespace(s, ch); - if(ch == '\0') { - ptmp = localuser; /* no remoteuser field */ - } else { - ptmp = s-1; /* start of remoteuser field */ - - /* Find end of remote user */ - skip_non_whitespace(s, ch); - s[-1] = '\0'; /* terminate remoteuser field */ - } -#if defined(SHOW_SECURITY_DETAIL) /* { */ - dbprintf(("%s: comparing %s with\n", debug_prefix(NULL), pbuf)); - dbprintf(("%s: %s (%s)\n", - debug_prefix(NULL), remotehost, - (strcasecmp(pbuf, remotehost) == 0) ? "match" : "no match")); - dbprintf(("%s: and %s with\n", debug_prefix(NULL), ptmp)); - dbprintf(("%s: %s (%s)\n", - debug_prefix(NULL), remoteuser, - (strcasecmp(ptmp, remoteuser) == 0) ? "match" : "no match")); -#endif /* } */ - if(strcasecmp(pbuf, remotehost) == 0 - && strcasecmp(ptmp, remoteuser) == 0) { - amandahostsauth = 1; - break; - } - memset(pbuf, '\0', pbuf_len); /* leave no trace */ - } - afclose(fPerm); - amfree(pbuf); - - if(amandahostsauth) { - dbprintf(("%s: amandahosts security check passed\n", - debug_prefix_time(NULL))); - amfree(remotehost); - amfree(localuser); - amfree(remoteuser); - return 1; - } - - *errstr = vstralloc("[", - "access as ", localuser, " not allowed", - " from ", remoteuser, "@", remotehost, - "] amandahostsauth failed", NULL); - dbprintf(("%s: check failed: %s\n", debug_prefix_time(NULL), *errstr)); - - amfree(remotehost); - amfree(localuser); - amfree(remoteuser); - return 0; - -#endif /* } */ + dbprintf(_("security_close(handle=%p, driver=%p (%s))\n"), + handle, handle->driver, + handle->driver->name); + amfree(handle->error); + (*handle->driver->close)(handle); } -#else /* ! BSD_SECURITY */ /* } { */ - -int bsd_security_ok(addr, str, cksum, errstr) -struct sockaddr_in *addr; -char *str; -uint32_t cksum; -char **errstr; +/* + * For the drivers: initialize the common part of a security_stream_t + */ +void +security_streaminit( + security_stream_t * stream, + const security_driver_t * driver) { -#if defined(SHOW_SECURITY_DETAIL) /* { */ - dbprintf(("You configured Amanda using --without-bsd-security, so it\n")); - dbprintf(("will let anyone on the Internet connect and do dumps of\n")); - dbprintf(("your system unless you have some other kind of protection,\n")); - dbprintf(("such as a firewall or TCP wrappers.\n")); -#endif /* } */ - return 1; + dbprintf(_("security_streaminit(stream=%p, driver=%p (%s))\n"), + stream, driver, driver->name); + stream->driver = driver; + stream->error = stralloc(_("unknown stream error")); } -#endif /* ! BSD_SECURITY */ /* } */ - -#if defined(TEST) /* { */ - -int -main (argc, argv) +printf_arglist_function1(void security_stream_seterror, + security_stream_t *, stream, + const char *, fmt) { - char *remoteuser; - char *remotehost; - struct hostent *hp; - struct sockaddr_in fake; - char *str; - char *errstr; - int r; - struct passwd *pwent; - - /* - * The following is stolen from amandad to emulate what it would - * do on startup. - */ - if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) { - client_uid = pwent->pw_uid; - client_gid = pwent->pw_gid; - endpwent(); - } -#ifdef FORCE_USERID - - /* we'd rather not run as root */ - if(geteuid() == 0) { -#ifdef KRB4_SECURITY - if(client_uid == (uid_t) -1) { - error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN); - } - - /* - * if we're using kerberos security, we'll need to be root in - * order to get at the machine's srvtab entry, so we hang on to - * some root privledges for now. We give them up entirely later. - */ - setegid(client_gid); - seteuid(client_uid); -#else - initgroups(CLIENT_LOGIN, client_gid); - setgid(client_gid); - setuid(client_uid); -#endif /* KRB4_SECURITY */ - } -#endif /* FORCE_USERID */ - - fputs("Remote user: ", stdout); - fflush(stdout); - if ((remoteuser = agets(stdin)) == NULL) { - return 0; - } - str = stralloc2("USER ", remoteuser); - - fputs("Remote host: ", stdout); - fflush(stdout); - if ((remotehost = agets(stdin)) == NULL) { - return 0; - } - - set_pname("security"); - startclock(); - - if ((hp = gethostbyname(remotehost)) == NULL) { - dbprintf(("%s: cannot look up remote host %s\n", - debug_prefix_time(NULL), remotehost)); - return 1; - } - memcpy((char *)&fake.sin_addr, (char *)hp->h_addr, sizeof(hp->h_addr)); - fake.sin_port = htons(IPPORT_RESERVED - 1); - - if ((r = bsd_security_ok(&fake, str, 0, &errstr)) == 0) { - dbprintf(("%s: security check of %s@%s failed\n", - debug_prefix_time(NULL), remoteuser, remotehost)); - dbprintf(("%s: %s\n", debug_prefix(NULL), errstr)); - } else { - dbprintf(("%s: security check of %s@%s passed\n", - debug_prefix_time(NULL), remoteuser, remotehost)); - } - return r; + static char buf[1024]; + va_list argp; + + arglist_start(argp, fmt); + g_vsnprintf(buf, SIZEOF(buf), fmt, argp); + arglist_end(argp); + stream->error = newstralloc(stream->error, buf); + dbprintf(_("security_stream_seterr(%p, %s)\n"), stream, stream->error); } -#endif /* } */ +void +security_stream_close( + security_stream_t * stream) +{ + dbprintf(_("security_stream_close(%p)\n"), stream); + amfree(stream->error); + (*stream->driver->stream_close)(stream); +}