* realm_dom.c (krb5_get_realm_domain): Don't indent #ifdef's!
[krb5.git] / src / lib / krb5 / os / hst_realm.c
1 /*
2  * lib/krb5/os/hst_realm.c
3  *
4  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * krb5_get_host_realm()
25  */
26
27
28 /*
29  Figures out the Kerberos realm names for host, filling in a
30  pointer to an argv[] style list of names, terminated with a null pointer.
31  
32  If host is NULL, the local host's realms are determined.
33
34  If there are no known realms for the host, the filled-in pointer is set
35  to NULL.
36
37  The pointer array and strings pointed to are all in allocated storage,
38  and should be freed by the caller when finished.
39
40  returns system errors
41 */
42
43 /*
44  * Implementation notes:
45  *
46  * this implementation only provides one realm per host, using the same
47  * mapping file used in kerberos v4.
48
49  * Given a fully-qualified domain-style primary host name,
50  * return the name of the Kerberos realm for the host.
51  * If the hostname contains no discernable domain, or an error occurs,
52  * return the local realm name, as supplied by krb5_get_default_realm().
53  * If the hostname contains a domain, but no translation is found,
54  * the hostname's domain is converted to upper-case and returned.
55  *
56  * The format of each line of the translation file is:
57  * domain_name kerberos_realm
58  * -or-
59  * host_name kerberos_realm
60  *
61  * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
62  * host names should be in the usual form (e.g. FOO.BAR.BAZ)
63  */
64
65 #define NEED_SOCKETS
66 #include "k5-int.h"
67 #include <ctype.h>
68 #include <stdio.h>
69 #ifdef USE_STRING_H
70 #include <string.h>
71 #else
72 #include <strings.h>
73 #endif
74
75 /* for old Unixes and friends ... */
76 #ifndef MAXHOSTNAMELEN
77 #define MAXHOSTNAMELEN 64
78 #endif
79
80 #define DEF_REALMNAME_SIZE      256
81
82 extern char *krb5_trans_file;
83
84 #ifdef _WINDOWS
85 /*
86  * Windows DLL can't use the fscanf routine. We need fscanf to read
87  * in the host and realm. Read_2str with read_1str duplicate the needed
88  * functionality. See also realm_dom.c.
89  */
90 static int
91 read_1str (FILE *fp, char *buf, int buflen) {
92     int c;
93
94     while (1) {
95         c = fgetc (fp);                         /* Past leading whitespace */
96         if (c == EOF)
97             return 0;
98         if (! isspace (c))
99             break;
100     }
101
102     while (1) {
103         if (buflen > 0) {                       /* Store the character */
104             *buf++ = (char) c;
105             --buflen;
106         }
107         if (buflen <= 0)                        /* Fscanf stops scanning... */
108             break;                              /* ...when buffer is full */
109
110         c = fgetc (fp);                         /* Get next character */
111         if (c == EOF || isspace (c))
112             break;
113     }
114
115     if (buflen)                                 /* Make ASCIIZ if room */
116         *buf = '\0';
117
118     return 1;
119 }
120
121 static int 
122 read_2str (FILE *fp, char *b1, int l1, char *b2, int l2) {
123     int n;
124
125     n = read_1str (fp, b1, l1);                 /* Read first string */
126     if (!n) return EOF;
127     n = read_1str (fp, b2, l2);                 /* Read second string */
128     if (!n) return 1;
129     return 2;
130 }
131
132 #endif /* _WINDOWS */
133
134 krb5_error_code INTERFACE
135 krb5_get_host_realm(context, host, realmsp)
136     krb5_context context;
137     const char *host;
138     char ***realmsp;
139 {
140     char **retrealms;
141     char *domain;
142     FILE *trans_file;
143     char trans_host[MAXHOSTNAMELEN+1];
144     char local_host[MAXHOSTNAMELEN+1];
145     char trans_realm[DEF_REALMNAME_SIZE];
146     krb5_error_code retval;
147     int scanval;
148     char scanstring[7+2*16];            /* 7 chars + 16 for each decimal
149                                            conversion */
150
151     if (!(retrealms = (char **)calloc(2, sizeof(*retrealms))))
152         return ENOMEM;
153     if (!host) {
154         if (gethostname(local_host, sizeof(local_host)-1) == -1)
155             return errno;
156         local_host[sizeof(local_host)-1] = '\0';
157         host = local_host;
158     }
159     domain = strchr(host, '.');
160
161     /* prepare default */
162     if (domain) {
163         char *cp;
164
165         if (!(retrealms[0] = malloc(strlen(&domain[1])+1))) {
166             krb5_xfree(retrealms);
167             return ENOMEM;
168         }
169         strcpy(retrealms[0], &domain[1]);
170         /* Upper-case realm */
171         for (cp = retrealms[0]; *cp; cp++)
172             if (islower(*cp))
173                 *cp = toupper(*cp);
174     } else {
175         if (retval = krb5_get_default_realm(context, &retrealms[0])) {
176             krb5_xfree(retrealms);
177             return retval;
178         }
179     }
180
181     krb5_find_config_files();
182     if ((trans_file = fopen(krb5_trans_file, "r")) == (FILE *) 0) {
183         krb5_xfree(retrealms[0]);
184         krb5_xfree(retrealms);
185         return KRB5_TRANS_CANTOPEN;
186     }
187     (void) sprintf(scanstring, "%%%ds %%%ds",
188                    sizeof(trans_host)-1,sizeof(trans_realm)-1);
189     while (1) {
190 #ifdef _WINDOWS
191             scanval = read_2str (trans_file, trans_host, sizeof(trans_host)-1,
192                 trans_realm, sizeof(trans_realm)-1);
193 #else
194             scanval = fscanf(trans_file, scanstring, trans_host, trans_realm);
195 #endif
196         if (scanval != 2) {
197             if (scanval == EOF) {
198                 fclose(trans_file);
199                 goto out;
200             }
201             continue;                   /* ignore broken lines */
202         }
203         trans_host[sizeof(trans_host)-1] = '\0';
204         trans_realm[sizeof(trans_realm)-1] = '\0';
205         if (!strcasecmp(trans_host, host)) {
206             /* exact match of hostname, so return the realm */
207             if (!(retrealms[0] = realloc(retrealms[0],
208                                          strlen(trans_realm)+1))) {
209                 krb5_xfree(retrealms);
210                 return ENOMEM;
211             }
212             (void) strcpy(retrealms[0], trans_realm);
213             fclose(trans_file);
214             goto out;
215         }
216         if ((trans_host[0] == '.') && domain) { 
217             /* this is a possible domain match */
218             if (!strcasecmp(trans_host, domain)) {
219                 /* domain match, save for later */
220                 if (!(retrealms[0] = realloc(retrealms[0],
221                                              strlen(trans_realm)+1))) {
222                     krb5_xfree(retrealms);
223                     return ENOMEM;
224                 }
225                 (void) strcpy(retrealms[0], trans_realm);
226                 continue;
227             }
228         }
229     }
230  out:
231     *realmsp = retrealms;
232     return 0;
233 }
234
235
236