From 92c81693a8d127571dbb2ee51010e8bc94a51bb2 Mon Sep 17 00:00:00 2001 From: Paul Park Date: Wed, 12 Jul 1995 18:57:20 +0000 Subject: [PATCH] Reorganize KDC profile and network port handling git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6287 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kdc/ChangeLog | 15 +++ src/kdc/extern.h | 2 + src/kdc/kdc_util.h | 4 +- src/kdc/krb5kdc.M | 22 +++- src/kdc/main.c | 273 ++++++++++++++++++++++++++++++++++++++++++--- src/kdc/network.c | 255 ++++++++++++++++++++++++++++++++++-------- 6 files changed, 505 insertions(+), 66 deletions(-) diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog index 554cc6140..4f708b140 100644 --- a/src/kdc/ChangeLog +++ b/src/kdc/ChangeLog @@ -1,3 +1,18 @@ + +Wed Jul 12 12:19:44 EDT 1995 Paul Park (pjpark@mit.edu) + * main.c - Reorganize KDC profile handling so that the hierarchy for + locating per-realm data is [realms]->realm->tag. Add + [kdcdefaults] section with primary_ports and secondary_ports + to list ports to listen on. Consolidate all port location here + from network.c. Add -s flag and change meaning of -p flag to + be the default if none specified in KDC or Kerberos profile. + * network.c - Open list of primary ports and then per-realm ports. + Handle secondary ports just like primary ports except that + bind failures are only warnings. Support more than one + secondary port. + * extern,kdc_util.h - Add supporting definitions. + * krb5kdc.M - update description of -p and add description of -s. + Tue Jul 11 07:35:12 1995 Ezra Peisach * kerberos_v4.c: Add prototype for set_tgtkey diff --git a/src/kdc/extern.h b/src/kdc/extern.h index fc9e57521..8b3bd8db4 100644 --- a/src/kdc/extern.h +++ b/src/kdc/extern.h @@ -32,6 +32,7 @@ typedef struct __kdc_realm_data { */ char * realm_name; /* Realm name */ krb5_context realm_context; /* Context to be used for realm */ + char * realm_profile; /* Profile file for this realm */ /* * Database per-realm data. */ @@ -52,6 +53,7 @@ typedef struct __kdc_realm_data { */ krb5_encrypt_block realm_encblock; /* Per-realm master encryption block*/ krb5_int32 realm_pport; /* Per-realm primary KDC port. */ + krb5_int32 realm_sport; /* Per-realm secondary KDC port. */ /* * Per-realm parameters. */ diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 605380f4c..5e3960c2f 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -95,7 +95,9 @@ krb5_error_code kdc_initialize_rcache PROTOTYPE((krb5_context, char *)); /* network.c */ krb5_error_code listen_and_process PROTOTYPE((const char *)); -krb5_error_code setup_network PROTOTYPE((const char *)); +krb5_error_code setup_network PROTOTYPE((const char *, + int *, + int *)); krb5_error_code closedown_network PROTOTYPE((const char *)); void process_packet PROTOTYPE((int, const char *, int)); diff --git a/src/kdc/krb5kdc.M b/src/kdc/krb5kdc.M index 89532585c..45af02434 100644 --- a/src/kdc/krb5kdc.M +++ b/src/kdc/krb5kdc.M @@ -38,6 +38,9 @@ krb5kdc \- Kerberos V5 KDC .B \-p .I portnum ] [ +.B \-s +.I portnum +] [ .B \-m ] [ .B \-r @@ -78,9 +81,22 @@ the default is KRB5_KDB_M_NAME (usually "K/M" in the KDC's realm). The .B \-p .I portnum -option specifies the UDP port number which the KDC should listen on for -requests. If none is specified, then the value in /etc/services is used, -with an ultimate default value of KRB5_DEFAULT_PORT, or 88. +option specifies the default UDP port number which the KDC should listen on for +Kerberos version 5 requests. This value is used when no port is specified in +the KDC profile and when no port is specified in the Kerberos configuration +file. +If no value is available, then the value in /etc/services for service +"kerberos" is used. +.PP +The +.B \-s +.I portnum +option specifies the default UDP port number which the KDC should listen on for +Kerberos version 4 requests. This value is used when no port is specified in +the kdc profile and when no port is specified in the Kerberos configuration +file. +If no value is available, then the value in /etc/services for service +"kerberos-sec" is used. .PP The .B \-m diff --git a/src/kdc/main.c b/src/kdc/main.c index 676d73852..6c046ba4f 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "com_err.h" #include "k5-int.h" @@ -55,6 +56,180 @@ static int rkey_init_done = 0; #define KRB5_KDC_MAX_REALMS 32 +/* + * Get port information for a realm. The precedence is: + * [realms]->-> in profile (if our hostname and has a port) + * defport + * /etc/services entry matching + */ +static krb5_int32 +get_realm_port(ctx, realm, name, defport, service) + krb5_context ctx; + char *realm; + char *name; + krb5_int32 defport; + char *service; +{ + krb5_error_code kret; + char our_host_name[MAXHOSTNAMELEN]; + struct hostent *our_hostent; + struct servent *our_servent; + krb5_int32 retval; + krb5_boolean found; + + /* + * Some preliminaries here. Get our hostname and our host entry. + */ + found = 0; + if (!gethostname(our_host_name, sizeof(our_host_name)) && + (our_hostent = gethostbyname(our_host_name))) { + const char *hierarchy[4]; + char **hostlist; + + hostlist = (char **) NULL; + hierarchy[0] = "realms"; + hierarchy[1] = realm; + hierarchy[2] = name; + hierarchy[3] = (char *) NULL; + if (!(kret = profile_get_values(ctx->profile, hierarchy, &hostlist))) { + int hi; + char *cport; + char *cp; + int ai; + krb5_int32 pport; + + cport = (char *) NULL; + for (hi=0; hostlist[hi]; hi++) { + /* + * This knows a little too much about the format of profile + * entries. Shouldn't it just be some sort of tuple? + * + * The form is assumed to be: + * = [:[]] + */ + pport = -1; + cp = strchr(hostlist[hi], ' '); + if (cp) + *cp = '\0'; + cp = strchr(hostlist[hi], '\t'); + if (cp) + *cp = '\0'; + cport = strchr(hostlist[hi], ':'); + if (cport) { + *cport = '\0'; + cport++; + if (sscanf(cport, "%d", &pport) == 1) { + pport = -1; + } + } + /* + * We've stripped away the crud. Now check to see if the + * profile entry matches our hostname. If so, then this + * is the one to use. Additionally, check the host alias + * list. + */ + if (!strcmp(hostlist[hi], our_hostent->h_name)) { + if (pport != -1) { + retval = pport; + found = 1; + } + } + else { + for (ai=0; our_hostent->h_aliases[ai]; ai++) { + if (!strcmp(hostlist[hi], + our_hostent->h_aliases[ai])) { + if (pport != -1) { + retval = pport; + found = 1; + } + break; + } + } + } + } + krb5_xfree(hostlist); + } + } + /* + * If we didn't find an entry in the profile, then use the default. + * If it's no good, then attempt to find it in /etc/services. + */ + if (!found) { + retval = defport; + /* Get the service entry out of /etc/services */ + if (retval <= 0) { + if (our_servent = getservbyname(service, "udp")) + retval = ntohs(our_servent->s_port); + } + } + return(retval); +} + +/* + * Convert a string of the form [,]* to a list of ints. + */ +static int * +string2intlist(string) + char *string; +{ + int nints, i; + char *cp; + int *intlist; + + for ((nints=1, cp=string); *cp; cp++) + if (*cp == ',') + nints++; + if (intlist = (int *) malloc((nints+1) * sizeof(int))) { + cp = string; + for (i=0; irealm_name = realm; if (!(kret = krb5_init_context(&rdp->realm_context))) { - hierarchy[0] = realm; - hierarchy[1] = "database_name"; - hierarchy[2] = (char *) NULL; + hierarchy[0] = "realms"; + hierarchy[1] = realm; + hierarchy[2] = "profile"; + hierarchy[3] = (char *) NULL; + /* + * Before any more per-realm initialization goes on, get the + * per-realm profile, if any. + */ + if (altp && !(kret = krb5_aprof_get_string(altp, + hierarchy, + TRUE, + &rdp->realm_profile))) { + const char *filenames[2]; + + /* + * XXX - this knows too much about contexts. + */ + filenames[0] = rdp->realm_profile; + filenames[1] = (char *) NULL; + if (rdp->realm_context->profile) + profile_release(rdp->realm_context->profile); + if (kret = profile_init(filenames, + &rdp->realm_context->profile)) { + com_err(progname, kret, + "while loading profile %s for realm %s", + rdp->realm_profile, realm); + goto whoops; + } + } + /* * Attempt to get the real value for the database file. */ + hierarchy[2] = "database_name"; if (!altp || (kret = krb5_aprof_get_string(altp, hierarchy, TRUE, @@ -205,7 +409,7 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, /* * Attempt to get the real value for the master key name. */ - hierarchy[1] = "master_key_name"; + hierarchy[2] = "master_key_name"; if (!altp || (kret = krb5_aprof_get_string(altp, hierarchy, TRUE, @@ -216,7 +420,7 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, /* * Attempt to get the real value for the master key type. */ - hierarchy[1] = "master_key_type"; + hierarchy[2] = "master_key_type"; if (!altp || (kret = krb5_aprof_get_int32(altp, hierarchy, TRUE, @@ -229,17 +433,37 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, /* * Attempt to get the real value for the primary port. */ - hierarchy[1] = "port"; + hierarchy[2] = "port"; if (!altp || (kret = krb5_aprof_get_int32(altp, hierarchy, TRUE, - &rdp->realm_pport))) - rdp->realm_pport = (def_port) ? def_port : KRB5_DEFAULT_PORT; + &rdp->realm_pport))) { + rdp->realm_pport = get_realm_port(rdp->realm_context, + realm, + "kdc", + def_port, + KDC_PORTNAME); + } + + /* + * Attempt to get the real value for the secondary port. + */ + hierarchy[2] = "secondary_port"; + if (!altp || (kret = krb5_aprof_get_int32(altp, + hierarchy, + TRUE, + &rdp->realm_sport))) { + rdp->realm_sport = get_realm_port(rdp->realm_context, + realm, + "v4kdc", + def_sport, + KDC_SECONDARY_PORTNAME); + } /* * Attempt to get the real value for the encryption type. */ - hierarchy[1] = "encryption_type"; + hierarchy[2] = "encryption_type"; if (!altp || (kret = krb5_aprof_get_int32(altp, hierarchy, TRUE, @@ -256,7 +480,7 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, /* * Attempt to get the real value for the stash file. */ - hierarchy[1] = "key_stash_file"; + hierarchy[2] = "key_stash_file"; if (!altp || (kret = krb5_aprof_get_string(altp, hierarchy, TRUE, @@ -268,7 +492,7 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, /* * Attempt to get the real value for the maximum ticket life. */ - hierarchy[1] = "max_life"; + hierarchy[2] = "max_life"; if (!altp || (kret = krb5_aprof_get_deltat(altp, hierarchy, TRUE, @@ -279,7 +503,7 @@ init_realm(progname, rdp, altp, realm, def_dbname, def_mpname, * Attempt to get the real value for the maximum renewable ticket * life. */ - hierarchy[1] = "max_renewable_life"; + hierarchy[2] = "max_renewable_life"; if (!altp || (kret = krb5_aprof_get_deltat(altp, hierarchy, TRUE, @@ -570,15 +794,16 @@ initialize_realms(kcontext, altp, argc, argv) krb5_enctype kdc_etype = DEFAULT_KDC_ETYPE; kdc_realm_t *rdatap; krb5_boolean manual = FALSE; - krb5_int32 pport; + krb5_int32 pport, sport; extern char *optarg; + pport = sport = -1; /* * Loop through the option list. Each time we encounter a realm name, * use the previously scanned options to fill in for defaults. */ - while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:n")) != EOF) { + while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n")) != EOF) { switch(c) { case 'r': /* realm name for db */ if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) { @@ -591,6 +816,7 @@ initialize_realms(kcontext, altp, argc, argv) mkey_name, mkeytype, pport, + sport, kdc_etype, manual)) { fprintf(stderr,"%s: cannot initialize realm %s\n", @@ -623,6 +849,9 @@ initialize_realms(kcontext, altp, argc, argv) case 'p': pport = atoi(optarg); break; + case 's': + sport = atoi(optarg); + break; case 'e': kdc_etype = atoi(optarg); break; @@ -652,6 +881,7 @@ initialize_realms(kcontext, altp, argc, argv) mkey_name, mkeytype, pport, + sport, kdc_etype, manual)) { fprintf(stderr,"%s: cannot initialize realm %s\n", @@ -720,6 +950,7 @@ char *argv[]; krb5_error_code retval; krb5_context kcontext; krb5_pointer alt_profile; + int *primaries, *secondaries; int errout = 0; if (strrchr(argv[0], '/')) @@ -732,6 +963,7 @@ char *argv[]; } memset((char *) kdc_realmlist, 0, (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS)); + primaries = secondaries = (int *) NULL; /* * A note about Kerberos contexts: This context, "kcontext", is used @@ -754,11 +986,16 @@ char *argv[]; */ initialize_realms(kcontext, alt_profile, argc, argv); + /* + * Get the default port lists. + */ + get_default_portlists(alt_profile, &primaries, &secondaries); + if (alt_profile) krb5_aprof_finish(alt_profile); setup_signal_handlers(); - if ((retval = setup_network(argv[0]))) { + if ((retval = setup_network(argv[0], primaries, secondaries))) { com_err(argv[0], retval, "while initializing network"); finish_realms(argv[0]); return 1; @@ -780,6 +1017,10 @@ char *argv[]; krb5_klog_syslog(LOG_INFO, "shutting down"); krb5_klog_close(kdc_context); finish_realms(argv[0]); + if (primaries) + free(primaries); + if (secondaries) + free(secondaries); return errout; } diff --git a/src/kdc/network.c b/src/kdc/network.c index b7eb556e6..60688e6b1 100644 --- a/src/kdc/network.c +++ b/src/kdc/network.c @@ -38,43 +38,64 @@ #include #endif #include -#include extern int errno; static int *udp_port_fds = (int *) NULL; static u_short *udp_port_nums = (u_short *) NULL; -static int sec_udp_port_fd = -1; +static int n_udp_ports = 0; +static int *sec_udp_port_fds = (int *) NULL; +static u_short *sec_udp_port_nums = (u_short *) NULL; +static int n_sec_udp_ports = 0; static fd_set select_fds; static int select_nfds; krb5_error_code -setup_network(prog) +setup_network(prog, p_ports, s_ports) const char *prog; +int *p_ports; +int *s_ports; { struct servent *sp; struct sockaddr_in sin; krb5_error_code retval; - u_short default_port; int i, j, found; + int npports, nsports; FD_ZERO(&select_fds); select_nfds = 0; memset((char *)&sin, 0, sizeof(sin)); - sp = getservbyname(KDC_PORTNAME, "udp"); - default_port = (sp) ? ntohs(sp->s_port) : KRB5_DEFAULT_PORT; - if ((udp_port_fds = (int *) malloc(kdc_numrealms * sizeof(int))) && - (udp_port_nums = (u_short *) malloc(kdc_numrealms * sizeof(u_short))) - ) { - for (i=0; i 0; npports++); + nsports = 0; + if (s_ports) + for (nsports=0; s_ports[nsports] > 0; nsports++); + + /* + * Now handle the primary ports. + */ + if ((udp_port_fds = (int *) malloc((kdc_numrealms+npports) + * sizeof(int))) && + (udp_port_nums = (u_short *) malloc((kdc_numrealms+npports) + * sizeof(u_short)))) { + /* Zero it out */ + for (i=0; i<(kdc_numrealms+npports); i++) { udp_port_fds[i] = -1; udp_port_nums[i] = 0; } - for (i=0; irealm_pport) { + if (udp_port_nums[j] == p_ports[i]) { found = 1; break; } @@ -83,17 +104,17 @@ const char *prog; if ((udp_port_fds[i] = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { retval = errno; com_err(prog, 0, "Cannot create server socket on port %d", - kdc_realmlist[i]->realm_pport); + p_ports[i]); return(retval); } - udp_port_nums[i] = kdc_realmlist[i]->realm_pport; - sin.sin_port = htons(kdc_realmlist[i]->realm_pport); + udp_port_nums[i] = p_ports[i]; + sin.sin_port = htons(p_ports[i]); if (bind(udp_port_fds[i], (struct sockaddr *) &sin, sizeof(sin)) == -1) { retval = errno; com_err(prog, 0, "Cannot bind server socket on port %d", - kdc_realmlist[i]->realm_pport); + p_ports[i]); return(retval); } FD_SET(udp_port_fds[i], &select_fds); @@ -105,33 +126,157 @@ const char *prog; udp_port_nums[i] = udp_port_nums[j]; } } + + /* Now handle each realm */ + for (i=0; irealm_pport) { + found = 1; + break; + } + } + if (!found) { + if ((udp_port_fds[npports+i] = + socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + retval = errno; + com_err(prog, 0, "Cannot create server socket on port %d", + kdc_realmlist[i]->realm_pport); + return(retval); + } + udp_port_nums[npports+i] = kdc_realmlist[i]->realm_pport; + sin.sin_port = htons(kdc_realmlist[i]->realm_pport); + if (bind(udp_port_fds[npports+i], + (struct sockaddr *) &sin, + sizeof(sin)) == -1) { + retval = errno; + com_err(prog, 0, "Cannot bind server socket on port %d", + kdc_realmlist[i]->realm_pport); + return(retval); + } + FD_SET(udp_port_fds[npports+i], &select_fds); + if (udp_port_fds[npports+i]+1 > select_nfds) + select_nfds = udp_port_fds[npports+i]+1; + } + else { + udp_port_fds[npports+i] = udp_port_fds[j]; + udp_port_nums[npports+i] = udp_port_nums[j]; + } + } + n_udp_ports = kdc_numrealms + npports; } /* - * Now we set up the secondary listening port + * Now we set up the secondary listening ports. Special case here. + * If the first secondary port is -1, then we don't listen on secondary + * ports. */ + if ((!s_ports || (s_ports[0] != -1)) && + (sec_udp_port_fds = (int *) malloc((kdc_numrealms+nsports) + * sizeof(int))) && + (sec_udp_port_nums = (u_short *) malloc((kdc_numrealms+nsports) + * sizeof(u_short)))) { + /* Zero it out */ + for (i=0; i<(kdc_numrealms+nsports); i++) { + sec_udp_port_fds[i] = -1; + sec_udp_port_nums[i] = 0; + } - sp = getservbyname(KDC_SECONDARY_PORTNAME, "udp"); - if (!sp && sin.sin_port == htons(KRB5_DEFAULT_SEC_PORT)) { - com_err(prog, 0, "%s/udp service unknown\n", - KDC_SECONDARY_PORTNAME); - return 0; /* Don't give an error if we can't */ - /* find it */ - } - if ((sec_udp_port_fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { - com_err(prog, errno, "while trying to create secondary server socket"); - return 0; /* Don't give an error we we can't do this */ - } - memset((char *)&sin, 0, sizeof(sin)); - sin.sin_port = sp ? sp->s_port : htons(KRB5_DEFAULT_SEC_PORT); - if (bind(sec_udp_port_fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { - com_err(prog, errno, "while trying to bind secondary server socket"); - return 0; /* Don't give an error if we can't do this */ + /* + * First handle any explicitly named secondary ports. + */ + for (i=0; i select_nfds) + select_nfds = sec_udp_port_fds[i]+1; + } + else { + sec_udp_port_fds[i] = sec_udp_port_fds[j]; + sec_udp_port_nums[i] = sec_udp_port_nums[j]; + } + } + + /* Now handle each realm */ + for (i=0; irealm_sport > 0) { + found = 0; + for (j=0; j<(nsports+i); j++) { + if (sec_udp_port_nums[j] == + kdc_realmlist[i]->realm_sport) { + found = 1; + break; + } + } + if (!found && (kdc_realmlist[i]->realm_sport > 0)) { + if ((sec_udp_port_fds[nsports+i] = + socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + retval = errno; + com_err(prog, 0, + "Cannot create secondary server socket on port %d", + kdc_realmlist[i]->realm_sport); + return(retval); + } + sec_udp_port_nums[nsports+i] = + kdc_realmlist[i]->realm_sport; + sin.sin_port = htons(kdc_realmlist[i]->realm_sport); + if (bind(sec_udp_port_fds[nsports+i], + (struct sockaddr *) &sin, + sizeof(sin)) == -1) { + retval = errno; + com_err(prog, 0, + "Cannot bind secondary server socket on port %d", + kdc_realmlist[i]->realm_sport); + close(sec_udp_port_fds[nsports+i]); + sec_udp_port_fds[nsports+i] = -1; + continue; + } + FD_SET(sec_udp_port_fds[nsports+i], &select_fds); + if (sec_udp_port_fds[nsports+i]+1 > select_nfds) + select_nfds = sec_udp_port_fds[nsports+i]+1; + } + else { + if (kdc_realmlist[i]->realm_sport > 0) { + sec_udp_port_fds[nsports+i] = sec_udp_port_fds[j]; + sec_udp_port_nums[nsports+i] = sec_udp_port_nums[j]; + } + else { + sec_udp_port_fds[nsports+i] = -1; + sec_udp_port_nums[nsports+i] = -1; + } + } + } + } + n_sec_udp_ports = kdc_numrealms + nsports; } - FD_SET(sec_udp_port_fd, &select_fds); - if (sec_udp_port_fd+1 > select_nfds) - select_nfds = sec_udp_port_fd+1; - return 0; } @@ -200,6 +345,7 @@ const char *prog; int nfound; fd_set readfds; int i; + int fdfound; if (udp_port_fds == (int *) NULL) return KDC5_NONET; @@ -213,13 +359,24 @@ const char *prog; com_err(prog, errno, "while selecting for network input"); continue; } - for (i=0; i 0) && FD_ISSET(sec_udp_port_fd, &readfds)) - process_packet(sec_udp_port_fd, prog, 1); + if (!fdfound) { + for (i=0; i= 0) + (void) close(udp_port_fds[i]); + } free(udp_port_fds); free(udp_port_nums); - if (sec_udp_port_fd != -1) - (void) close(sec_udp_port_fd); - sec_udp_port_fd = -1; + for (i=0; i= 0) + (void) close(sec_udp_port_fds[i]); + } + free(sec_udp_port_fds); + free(sec_udp_port_nums); + return 0; } -- 2.26.2