source: trunk/athena/bin/discuss/libds/res_module.c @ 23815

Revision 23815, 8.8 KB checked in by broder, 15 years ago (diff)
In discuss: * Assorted changes to make discuss work with any combination of krb4 and krb5 (including neither).
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *
10 *      $Id: res_module.c,v 1.18 2007-08-09 20:41:32 amb Exp $
11 *
12 * resolve_module () --
13 *      Can you say "Put all the configuration into one file?"  Can you
14 *      say "Concentrated kludgery?"  I knew you could.  This procedure
15 *      resolves a module name into port number, hostname, service; it
16 *      is allowed to use any trick in the book -- it can depend on hostnames,
17 *      have hard coded constants (hopefully recorded in config files, etc.).
18 *      Note that if service name contains a '/' as the first character, then
19 *      the remote function is executed as a subprocess.
20 *
21 */
22
23#ifndef lint
24static char rcsid_res_module_c[] =
25    "$Id: res_module.c,v 1.18 2007-08-09 20:41:32 amb Exp $";
26#endif /* lint */
27
28#include "rpc_et.h"
29#include "config.h"
30#include "ansi.h"
31#include <stdio.h>
32#include <netdb.h>
33#include <string.h>
34#include <ctype.h>
35
36#ifdef HAVE_KRB4
37#include <krb.h>
38#ifndef MAX_K_NAME_SZ
39/* @#$%^$ last minute changes by jtkohl */
40#define krb_get_lrealm get_krbrlm
41#endif
42#endif /* HAVE_KRB4 */
43
44#ifdef HAVE_KRB5
45#include <krb5.h>
46#endif /* HAVE_KRB5 */
47
48#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
49static void ExpandHost ();
50#endif /* HAVE_KRB5 || HAVE_KRB4 */
51
52#ifndef SNAME_SZ
53#define SNAME_SZ 30
54#define REALM_SZ 30
55#endif /* SNAME_SZ */
56
57char *local_host_name ();
58const char *local_realm ();
59
60static int service_port = 0;
61
62/* sys/param.h for MAXPATHLEN */
63#include <sys/param.h>
64/* sys/types.h and sys/stat.h for stat() */
65#include <sys/types.h>
66#include <sys/stat.h>
67static char *path_search(base)
68    char *base;                 /* filename to search for */
69{
70    char *getenv();
71    char *path=getenv("PATH");
72    static char val[MAXPATHLEN];
73    char *valp;
74    struct stat s;
75   
76    if(!path) return 0;
77    while(*path) {
78        valp = val;
79        while(*path && (*path != ':')) {
80            *(valp++) = *(path++);
81        }
82        if(*path == ':') path++;
83        *(valp++) = '/';
84        strcpy(valp,base);
85        if(0 == stat(val,&s)) {
86            if((s.st_mode & (S_IEXEC|S_IFREG)) == (S_IEXEC|S_IFREG)) {
87                return val;
88            }
89        }
90    }
91    return 0;
92}
93
94void resolve_module (modname, port, hostp, servp, result)
95    char *modname;              /* name to translate */
96    int *port;                  /* resultant port number */
97    char **hostp;               /* ptr to hostname (static) */
98    char **servp;               /* service_id */
99    int *result;                /* std error code */
100{
101    static char service_id [SNAME_SZ+REALM_SZ];
102    static char hostname [BUFSIZ];
103    char realm [REALM_SZ];
104
105    char *myhnamep = NULL;
106    const char *realmp = NULL;
107    struct servent *sp;
108    struct hostent *hp;
109
110    *hostp = NULL;
111    *servp = NULL;
112    *port = 0;
113    *result = 0;
114
115    /* The module name could be of the form "discuss@hostname", where
116     * hostname is the host to contact.  If the hostname is omitted,
117     * the current host is assumed */
118    if (!strncmp (modname, "discuss", 7)) {
119        if (modname [7] == '@') { /* got hostname */
120            myhnamep = &modname [8];
121            /* if the name is blank, use *unprotected* local host and file. */
122            if(*myhnamep == 0) {
123                myhnamep = "";
124            } else {
125                hp = gethostbyname (myhnamep); /* make it primary */
126                if (!hp) {
127                    extern int h_errno;
128                    int h = h_errno;
129                    switch (h) {
130                    case HOST_NOT_FOUND:
131                        *result = RPC_HOST_UNKNOWN;
132                        break;
133                    case TRY_AGAIN:
134                        *result = RPC_NS_TIMEOUT;
135                        break;
136                    case NO_RECOVERY:
137                        *result = RPC_NS_ERROR;
138                        break;
139                    case NO_ADDRESS:
140                        *result = RPC_NO_ADDR;
141                        break;
142                        default:
143                        *result = RPC_NS_ERROR;
144                    }
145                    return;
146                }
147                strcpy (hostname, hp -> h_name);
148                myhnamep = hostname;
149            }
150        } else if (modname [7] == '\0') { /* Just discuss - use current host */
151            myhnamep = local_host_name ();
152        } else {
153            *result = RPC_MOD_UNKNOWN;
154            return;
155        }
156    }
157
158#if 0
159    /* or... the module could be of the form of disname@realm, where realm
160     * is a kerberos realm.  If realm is not given, then the current realm
161     * is assumed. */
162    else if (!strncmp (modname, "disname", 7)) {
163        if (modname [7] == '@') {               /* got realm */
164            realmp = &modname [8];
165        } else if (modname [7] == '\0') {
166            /* Just disname - use current realm */
167            realmp = local_realm ();
168        } else {
169            *result = RPC_MOD_UNKNOWN;
170            return;
171        }
172
173        /* got realm -- use our static lookup. */
174        if (!strcmp (realmp, "LCS.MIT.EDU"))
175            myhnamep = "GRAPE-NEHI.LCS.MIT.EDU";
176        else if (!strcmp (realmp, "ATHENA.MIT.EDU"))
177            myhnamep = "CHARON.MIT.EDU";
178        else {
179            *result = RPC_REALM_UNKNOWN;
180            return;
181        }
182    }
183#endif
184    else {
185        *result = RPC_MOD_UNKNOWN;
186        return;
187    }
188
189    /* Now we have the host name, and all we have to do is create the
190     * service id & port number. */
191
192    /* If this is in a local file, we use filesystem authentication
193     * and run the non-subsystem subprocess. */
194    if (myhnamep[0] == 0) {
195        *port = 0;
196        *servp = SERVER_LOCAL;
197        if(SERVER_LOCAL[0] != '/') {
198            /* path search for disserve */
199            char *pathval=path_search(SERVER_LOCAL);
200            if(pathval) {
201                *servp = pathval;
202            } else {
203                /* should perhaps inaugurate a new error type? */
204                *result = RPC_MOD_UNKNOWN;
205                return;
206            }
207        }
208        *hostp = myhnamep;
209        *result = 0;
210        return;
211    }
212
213   
214    /* If this is local, we use the subprocess,
215     * for better authentication */
216    if (!namcmp (myhnamep, local_host_name ())) {
217        *port = 0;
218        *servp = SERVER;
219        *hostp = myhnamep;
220        *result = 0;
221        return;
222    }
223
224    /* otherwise, we have to generate the port number */
225    if (service_port == 0) {
226        sp = getservbyname (SERVICE_NAME, "tcp");
227        service_port = (sp) ? sp->s_port : htons(DISCUSS_FALLBACK_PORT);
228    }
229
230    *port = service_port;
231
232    /* generate the service name, but concatenating "discuss.instance@realm"
233     * desired realm. */
234    strcpy (service_id, "discuss");
235#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
236#ifdef HAVE_KRB5
237    strcat (service_id, "/");
238#else
239    strcat (service_id, ".");
240#endif
241    ExpandHost (myhnamep, &service_id[8], realm);
242    strcat(service_id, "@");
243    if (realmp)
244        strcat (service_id, realmp);
245    else
246        strcat (service_id, realm);
247#else /* HAVE_KRB5 || HAVE_KRB4 */
248    strcat (service_id, "@");
249    strcpy (&service_id[8], REALM);
250#endif /* HAVE_KRB5 || HAVE_KRB4 */
251    *hostp = myhnamep;
252    *servp = service_id;
253    *result = 0;
254}
255
256#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
257/*
258 *
259 * ExpandHost -- takes a user string alias for a host, and converts it
260 *               to the official Kerberos principal name, plus the realm
261 *               that it lies in.
262 *
263 *     Warning:  There are some heuristics here.
264 *
265 */
266
267static void ExpandHost (primary_name, krb_host, krb_realm )
268    char *primary_name,*krb_realm;
269    char *krb_host;
270{
271    char *p,*sp=primary_name,*dp=krb_host;
272    /*
273     * The convention established by the Kerberos-authenticated
274     * rcmd services (rlogin, rsh, rcp) is that the principal host
275     * name is all lower case characters.  Therefore, we can get
276     * this name from an alias by taking the official, fully
277     * qualified hostname, stripping off the domain info (ie, take
278     * everything up to but excluding the '.') and translating it
279     * to lower case.  For example, if "menel" is an alias for
280     * host officially named "menelaus" (in /etc/hosts), for the
281     * host whose official name is "MENELAUS.MIT.EDU", the user
282     * could give the command "menel echo foo" and we will resolve
283     * it to "menelaus".
284     */
285#ifdef HAVE_KRB5
286    krb5_context context;
287    char **hrealms = 0;
288    krb5_error_code retval;
289
290    retval = krb5_init_context(&context);
291    if (!retval)
292      krb5_get_host_realm(context, primary_name, &hrealms);
293    if (!retval && !hrealms[0])
294      strcpy(krb_realm, hrealms[0]);
295    if (retval)
296      strcpy(krb_realm, local_realm());
297
298    if (hrealms)
299      krb5_free_host_realm(context, hrealms);
300    if (context)
301      krb5_free_context(context);
302#else /* HAVE_KRB5 */
303    (void) strcpy(krb_realm, (char *)krb_realmofhost(primary_name));
304#endif
305    /* lower case Kerberos host name */
306    do {
307        if (isupper(*sp)) *dp=tolower(*sp);
308        else *dp = *sp;
309#ifdef HAVE_KRB5
310    } while (dp++,*sp++);
311#else
312    } while (dp++,*sp && (*sp++ != '.'));
313#endif /* HAVE_KRB5 */
314    *(--dp) = 0;
315
316    /* heuristics */
317
318    if (*krb_realm == '\0')
319        strcpy (krb_realm, local_realm());
320#ifdef notdef
321    if (!strcmp(krb_realm,"MIT.EDU"))
322        strcpy(krb_realm,"ATHENA.MIT.EDU");
323#endif
324    return;
325}
326#endif /* HAVE_KRB4 || HAVE_KRB5 */
327
328const char *local_realm ()
329{
330#ifdef HAVE_KRB4
331    static char realm [REALM_SZ] = "";
332
333    if (realm [0] == '\0')
334        krb_get_lrealm (realm, 1);
335
336    return (realm);
337#elif defined(HAVE_KRB5)
338    krb5_context context;
339    static char *realm = NULL;
340
341    if (!realm) {
342      krb5_init_context(&context);
343      krb5_get_default_realm(context, &realm);
344      krb5_free_context(context);
345    }
346
347    return realm;
348#else /* HAVE_KRB4 */
349    return (REALM);
350#endif /* HAVE_KRB4 */
351}
Note: See TracBrowser for help on using the repository browser.