]> andersk Git - moira.git/blob - server/mr_sauth.c
Build without krb4 if it's unavailable.
[moira.git] / server / mr_sauth.c
1 /* $Id$
2  *
3  * Handle server side of authentication
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13
14 #include <sys/types.h>
15
16 #include <arpa/inet.h>
17 #include <netinet/in.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 RCSID("$Header$");
23
24 extern char *whoami, *host;
25 extern int proxy_acl;
26 extern krb5_context context;
27
28 static int set_client(client *cl, char *kname,
29                       char *name, char *inst, char *realm);
30
31 #ifdef HAVE_KRB4
32 typedef struct _replay_cache {
33   KTEXT_ST auth;
34   time_t expires;
35   struct _replay_cache *next;
36 } replay_cache;
37
38 replay_cache *rcache = NULL;
39 #endif
40
41 /*
42  * Handle a MOIRA_AUTH RPC request.
43  *
44  * argv[0] is a kerberos authenticator.  Decompose it, and if
45  * successful, store the name the user authenticated to in
46  * cl->cl_name.
47  */
48
49 void do_auth(client *cl)
50 {
51 #ifdef HAVE_KRB4
52   KTEXT_ST auth;
53   AUTH_DAT ad;
54   int status;
55   replay_cache *rc, *rcnew;
56   time_t now;
57
58   auth.length = cl->req.mr_argl[0];
59   memcpy(auth.dat, cl->req.mr_argv[0], auth.length);
60   auth.mbz = 0;
61
62   if ((status = krb_rd_req(&auth, MOIRA_SNAME, host,
63                            cl->haddr.sin_addr.s_addr, &ad, "")))
64     {
65       status += ERROR_TABLE_BASE_krb;
66       client_reply(cl, status);
67       com_err(whoami, status, " (authentication failed)");
68       return;
69     }
70
71   if (!rcache)
72     {
73       rcache = xmalloc(sizeof(replay_cache));
74       memset(rcache, 0, sizeof(replay_cache));
75     }
76
77   /* scan replay cache */
78   for (rc = rcache->next; rc; rc = rc->next)
79     {
80       if (auth.length == rc->auth.length &&
81           !memcmp(&(auth.dat), &(rc->auth.dat), auth.length))
82         {
83           com_err(whoami, 0,
84                   "Authenticator replay from %s using authenticator for %s",
85                   inet_ntoa(cl->haddr.sin_addr),
86                   mr_kname_unparse(ad.pname, ad.pinst, ad.prealm));
87           com_err(whoami, KE_RD_AP_REPEAT, " (authentication failed)");
88           client_reply(cl, KE_RD_AP_REPEAT);
89           return;
90         }
91     }
92
93   /* add new entry */
94   time(&now);
95   rcnew = xmalloc(sizeof(replay_cache));
96   memcpy(&(rcnew->auth), &auth, sizeof(KTEXT_ST));
97   rcnew->expires = now + 2 * CLOCK_SKEW;
98   rcnew->next = rcache->next;
99   rcache->next = rcnew;
100
101   /* clean cache */
102   for (rc = rcnew; rc->next; )
103     {
104       if (rc->next->expires < now)
105         {
106           rcnew = rc->next;
107           rc->next = rc->next->next;
108           free(rcnew);
109         }
110       else
111         rc = rc->next;
112     }
113
114   status = set_client(cl, mr_kname_unparse(ad.pname, ad.pinst, ad.prealm),
115                       ad.pname, ad.pinst, ad.prealm);
116
117   strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
118   cl->entity[sizeof(cl->entity) - 1] = 0;
119
120   memset(&ad, 0, sizeof(ad));   /* Clean up session key, etc. */
121
122   com_err(whoami, 0, "Auth to %s using %s, uid %d cid %d",
123           cl->clname, cl->entity, cl->users_id, cl->client_id);
124
125   if (status != MR_SUCCESS || cl->users_id != 0)
126     client_reply(cl, status);
127   else
128     client_reply(cl, MR_USER_AUTH);
129 #else
130   client_reply(cl, MR_NO_KRB4);
131 #endif
132 }
133
134 void do_proxy(client *cl)
135 {
136   char name[ANAME_SZ] = "\0", inst[INST_SZ] = "\0", realm[REALM_SZ] = "\0";
137   char kname[MAX_K_NAME_SZ];
138
139   if (cl->proxy_id)
140     {
141       com_err(whoami, MR_PERM, "Cannot re-proxy");
142       client_reply(cl, MR_PERM);
143       return;
144     }
145
146   if (mr_kname_parse(name, inst, realm, cl->req.mr_argv[0]) != 0)
147     {
148       com_err(whoami, KE_KNAME_FMT, "while parsing proxy name %s",
149               cl->req.mr_argv);
150       client_reply(cl, KE_KNAME_FMT);
151       return;
152     }
153
154   if (!*realm)
155     {
156       strcpy(realm, krb_realm);
157       sprintf(kname, "%s@%s", cl->req.mr_argv[0], realm);
158     }
159   else
160     strcpy(kname, cl->req.mr_argv[0]);
161     
162   if (find_member("LIST", proxy_acl, cl))
163     {
164       cl->proxy_id = cl->client_id;
165       set_client(cl, kname, name, inst, realm);
166       com_err(whoami, 0, "Proxy authentication as %s (uid %d cid %d) via %s",
167               kname, cl->users_id, cl->client_id, cl->req.mr_argv[1]);
168       client_reply(cl, MR_SUCCESS);
169     }
170   else
171     {
172       com_err(whoami, MR_PERM, "Proxy authentication denied");
173       client_reply(cl, MR_PERM);
174     }
175 }
176
177 static int set_client(client *cl, char *kname,
178                       char *name, char *inst, char *realm)
179 {
180   int ok;
181
182   strncpy(cl->clname, kname, sizeof(cl->clname));
183   cl->clname[sizeof(cl->clname) - 1] = '\0';
184
185   if ((!inst || inst[0] == 0) && !strcmp(realm, krb_realm))
186     ok = 1;
187   else
188     ok = 0;
189   /* this is in a separate function because it accesses the database */
190   return set_krb_mapping(cl->clname, name, ok, &cl->client_id, &cl->users_id);
191 }
192
193 void do_krb5_auth(client *cl)
194 {
195   krb5_data auth;
196   krb5_auth_context auth_con = NULL;
197   krb5_principal server = NULL, client = NULL;
198   krb5_ticket *ticket;
199   char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
200   int status;
201
202   ticket = NULL;
203
204   status = krb5_auth_con_init(context, &auth_con);
205   if (status)
206     {
207       client_reply(cl, status);
208       com_err(whoami, status, "(krb5 auth context init failed)");
209       goto out;
210     }
211
212   status = krb5_sname_to_principal(context, host, MOIRA_SNAME, 
213                                     KRB5_NT_SRV_HST, &server);
214   if (status)
215     {
216       client_reply(cl, status);
217       com_err(whoami, status, "(krb5_sname_to_principal failed)");
218       goto out;
219     }
220
221   auth.length = cl->req.mr_argl[0];
222   auth.data = cl->req.mr_argv[0];
223
224   status = krb5_rd_req(context, &auth_con, &auth, server, NULL, NULL,
225                         &ticket);
226   if (status)
227     {
228       client_reply(cl, status);
229       com_err(whoami, status, " (krb5 authentication failed)");
230       goto out;
231     }
232
233   status = krb5_copy_principal(context, ticket->enc_part2->client, &client);
234   if (status)
235     {
236       client_reply(cl, status);
237       com_err(whoami, status, " (krb5_copy_principal failed)");
238       goto out;
239     }
240
241   /* Always convert to krb4 style principal name for now. */
242   status = krb5_524_conv_principal(context, client, name, inst, realm);
243   if (status)
244     {
245       client_reply(cl, status);
246       com_err(whoami, status, " (krb5_524_conv_principal failed)");
247       goto out;
248     }
249   status = set_client(cl, mr_kname_unparse(name, inst, realm), name, inst,
250                       realm);
251
252   strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
253   cl->entity[sizeof(cl->entity) - 1] = 0;
254
255   com_err(whoami, 0, "krb5 auth to %s using %s, uid %d cid %d",
256           cl->clname, cl->entity, cl->users_id, cl->client_id);
257
258   if (status != MR_SUCCESS || cl->users_id != 0)
259     client_reply(cl, status);
260   else
261     client_reply(cl, MR_USER_AUTH);
262
263  out:
264   if (client)
265     krb5_free_principal(context, client);
266   if (server)
267     krb5_free_principal(context, server);
268   if (ticket)
269     krb5_free_ticket(context, ticket);
270   if (auth_con)
271     krb5_auth_con_free(context, auth_con);
272   return;
273 }
This page took 0.058821 seconds and 5 git commands to generate.