Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / walk_rtree.c
1 /*
2  * lib/krb5/krb/walk_rtree.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_walk_realm_tree()
25  */
26
27 #include "k5-int.h"
28 #include "int-proto.h"
29
30 /* internal function, used by krb5_get_cred_from_kdc() */
31
32 #ifndef min
33 #define min(x,y) ((x) < (y) ? (x) : (y))
34 #define max(x,y) ((x) > (y) ? (x) : (y))
35 #endif
36
37 krb5_error_code
38 krb5_walk_realm_tree(context, client, server, tree, realm_branch_char)
39     krb5_context context;
40     const krb5_data *client, *server;
41     krb5_principal **tree;
42     int realm_branch_char;
43 {
44     krb5_error_code retval;
45     krb5_principal *rettree;
46     register char *ccp, *scp;
47     register char *prevccp = 0, *prevscp = 0;
48     char *com_sdot = 0, *com_cdot = 0;
49     register int i, links = 0;
50     int clen, slen;
51     krb5_data tmpcrealm, tmpsrealm;
52     int nocommon = 1;
53
54     clen = client->length;
55     slen = server->length;
56
57     for (com_cdot = ccp = client->data + clen - 1,
58          com_sdot = scp = server->data + slen - 1;
59          clen && slen && *ccp == *scp ;
60          ccp--, scp--,  clen--, slen--) {
61         if (*ccp == realm_branch_char) {
62             com_cdot = ccp;
63             com_sdot = scp;
64             nocommon = 0;
65         }
66     }
67
68     /* ccp, scp point to common root.
69        com_cdot, com_sdot point to common components. */
70     /* handle case of one ran out */
71     if (!clen) {
72         /* construct path from client to server, down the tree */
73         if (!slen)
74             /* in the same realm--this means there is no ticket
75                in this realm. */
76             return KRB5_NO_TKT_IN_RLM;
77         if (*scp == realm_branch_char) {
78             /* one is a subdomain of the other */
79             com_cdot = client->data;
80             com_sdot = scp;
81             nocommon = 0;
82         } /* else normal case of two sharing parents */
83     }
84     if (!slen) {
85         /* construct path from client to server, up the tree */
86         if (*ccp == realm_branch_char) {
87             /* one is a subdomain of the other */
88             com_sdot = server->data;
89             com_cdot = ccp;
90             nocommon = 0;
91         } /* else normal case of two sharing parents */
92     }
93     /* determine #links to/from common ancestor */
94     if (nocommon)
95         links = 1;
96     else
97         links = 2;
98     /* if no common ancestor, artificially set up common root at the last
99        component, then join with special code */
100     for (ccp = client->data; ccp < com_cdot; ccp++) {
101         if (*ccp == realm_branch_char) {
102             links++;
103             if (nocommon)
104                 prevccp = ccp;
105         }
106     }
107
108     for (scp = server->data; scp < com_sdot; scp++) {
109         if (*scp == realm_branch_char) {
110             links++;
111             if (nocommon)
112                 prevscp = scp;
113         }
114     }
115     if (nocommon) {
116         if (prevccp)
117             com_cdot = prevccp;
118         if (prevscp)
119             com_sdot = prevscp;
120
121         if(com_cdot == client->data + client->length -1)
122            com_cdot = client->data - 1 ;
123         if(com_sdot == server->data + server->length -1)
124            com_sdot = server->data - 1 ;
125     }
126
127     if (!(rettree = (krb5_principal *)calloc(links+2,
128                                              sizeof(krb5_principal)))) {
129         return ENOMEM;
130     }
131     i = 1;
132     if (retval = krb5_tgtname(context, client,
133                               client, &rettree[0])) {
134         krb5_xfree(rettree);
135         return retval;
136     }
137     for (prevccp = ccp = client->data;
138          ccp <= com_cdot;
139          ccp++) {
140         if (*ccp != realm_branch_char)
141             continue;
142         ++ccp;                          /* advance past dot */
143         tmpcrealm.data = prevccp;
144         tmpcrealm.length = client->length -
145             (prevccp - client->data);
146         tmpsrealm.data = ccp;
147         tmpsrealm.length = client->length -
148             (ccp - client->data);
149         if (retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i])) {
150             while (i) {
151                 krb5_free_principal(context, rettree[i-1]);
152                 i--;
153             }
154             krb5_xfree(rettree);
155             return retval;
156         }
157         prevccp = ccp;
158         i++;
159     }
160     if (nocommon) {
161         tmpcrealm.data = com_cdot + 1;
162         tmpcrealm.length = client->length -
163             (com_cdot + 1 - client->data);
164         tmpsrealm.data = com_sdot + 1;
165         tmpsrealm.length = server->length -
166             (com_sdot + 1 - server->data);
167         if (retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i])) {
168             while (i) {
169                 krb5_free_principal(context, rettree[i-1]);
170                 i--;
171             }
172             krb5_xfree(rettree);
173             return retval;
174         }
175         i++;
176     }
177
178     for (prevscp = com_sdot + 1, scp = com_sdot - 1;
179          scp > server->data;
180          scp--) {
181         if (*scp != realm_branch_char)
182             continue;
183         if (scp - 1 < server->data)
184             break;                      /* XXX only if . starts realm? */
185         tmpcrealm.data = prevscp;
186         tmpcrealm.length = server->length -
187             (prevscp - server->data);
188         tmpsrealm.data = scp + 1;
189         tmpsrealm.length = server->length -
190             (scp + 1 - server->data);
191         if (retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i])) {
192             while (i) {
193                 krb5_free_principal(context, rettree[i-1]);
194                 i--;
195             }
196             krb5_xfree(rettree);
197             return retval;
198         }
199         prevscp = scp + 1;
200         i++;
201     }
202     if (slen && com_sdot >= server->data) {
203         /* only necessary if building down tree from ancestor or client */
204         /* however, we can get here if we have only one component
205            in the server realm name, hence we make sure we found a component
206            separator there... */
207         tmpcrealm.data = prevscp;
208         tmpcrealm.length = server->length -
209             (prevscp - server->data);
210         if (retval = krb5_tgtname(context, server, &tmpcrealm,
211                                   &rettree[i])) {
212             while (i) {
213                 krb5_free_principal(context, rettree[i-1]);
214                 i--;
215             }
216             krb5_xfree(rettree);
217             return retval;
218         }
219     }
220     *tree = rettree;
221     return 0;
222 }