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