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

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