]> andersk Git - moira.git/blob - reg_svr/requests.c
RSAREF (for new reg_svr)
[moira.git] / reg_svr / requests.c
1 /* $Id$
2  *
3  * Server for user registration with Moira and Kerberos.
4  *
5  * This file handles the processing of requests for the register
6  * server.
7  *
8  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
9  * For copying and distribution information, please see the file
10  * <mit-copyright.h>.
11  */
12
13 #include <mit-copyright.h>
14 #include <moira.h>
15 #include <moira_site.h>
16
17 #include <sys/types.h>
18 #include <sys/socket.h>
19
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <netdb.h>
23
24 #include <errno.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "reg_svr.h"
29
30 RCSID("$Header$");
31
32 #define NUM_REQUESTS_SAVED 100  /* Number of transactions to save */
33 #define CUR_REQ (requests[cur_request_index]) /* The current request */
34 #define NEXT_INDEX(x)  (x == NUM_REQUESTS_SAVED - 1) ? 0 : (x + 1)
35 #define PREV_INDEX(x)  (x == 0) ? (NUM_REQUESTS_SAVED - 1) : (x - 1)
36
37 static struct servent *sp;      /* Service info from /etc/services */
38 static int s;                   /* Socket descriptor */
39 static struct sockaddr_in sin;  /* Internet style socket address */
40 static int addrlen;             /* Size of socket address (sin) */
41
42 /* In order to elegantly handle multiple retransmissions, an instance
43    of this structure will be retained for the last NUM_REQUESTS_SAVED
44    transactions with the client. */
45 struct request_save {
46   char out_pkt[BUFSIZ];         /* Buffer for outgoing packet */
47   int out_pktlen;               /* Length of outgoing packet */
48   U_32BIT seqno;                /* Sequence number for packet transmission */
49   u_long ip_address;            /* Internet address of client host */
50   u_short cl_port;              /* Port number client used */
51 };
52
53 static struct request_save requests[NUM_REQUESTS_SAVED]; /* Saved packets */
54 static int cur_request_index = 0;       /* Index to the current request */
55
56 void clear_req(struct request_save *req);
57 void req_initialize(void);
58 int handle_retransmitted(void);
59 void respond(int status, char *text);
60 void get_request(struct msg *message);
61 void report(int status, char *message);
62 int format_pkt(char *packet, int *pktlenp, U_32BIT seqno,
63                int cl_status, char *message);
64 int ureg_validate_char(char *s);
65 int parse_pkt(char *packet, int pktlen, struct msg *message);
66 u_long cur_req_sender(void);
67
68 void clear_req(struct request_save *req)
69 {
70   req->seqno = 0;
71   req->ip_address = 0;
72   req->cl_port = 0;
73 }
74
75 void req_initialize(void)
76 {
77   int i;
78
79   /* Get service information from /etc/services */
80   if (!(sp = getservbyname("moira_ureg", "udp")))
81     {
82       com_err(whoami, errno, " unknown service moira_ureg/udp");
83       exit(1);
84     }
85
86   /* Get an internet style datagram socket */
87   if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
88     {
89       com_err(whoami, errno, " socket");
90       exit(1);
91     }
92   memset(&sin, 0, sizeof(sin));
93
94   sin.sin_family = AF_INET;
95   sin.sin_port = sp->s_port;
96   sin.sin_addr.s_addr = INADDR_ANY;
97
98   /* Bind a name to the socket */
99   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
100     {
101       com_err(whoami, errno, " bind");
102       exit(1);
103     }
104
105   for (i = 0; i < NUM_REQUESTS_SAVED; i++)
106     clear_req(&(requests[i]));
107 }
108
109 int handle_retransmitted(void)
110 {
111   int i;                        /* A counter */
112   int status = FALSE;           /* Return status */
113
114   for (i = PREV_INDEX(cur_request_index); i != cur_request_index;
115        i = PREV_INDEX(i))
116     {
117       if ((requests[i].seqno == CUR_REQ.seqno) &&
118           (requests[i].ip_address == sin.sin_addr.s_addr) &&
119           (requests[i].cl_port == sin.sin_port))
120         /* This is a retransmitted packet */
121         {
122           status = TRUE;
123           sendto(s, requests[i].out_pkt, requests[i].out_pktlen,
124                  0, (struct sockaddr *)&sin, addrlen);
125           break;
126         }
127     }
128
129   return status;
130 }
131
132 /* This routine takes care of sending packets back to the client and
133    caching the necessary information for retransmission detection.
134    It is the only place in which cur_request_index should be
135    changed. */
136 void respond(int status, char *text)
137 {
138   CUR_REQ.out_pktlen = sizeof(CUR_REQ.out_pkt);
139
140   if (format_pkt(CUR_REQ.out_pkt, &(CUR_REQ.out_pktlen),
141                  CUR_REQ.seqno, status, text))
142     com_err(whoami, 0, "Client error message was truncated.");
143   sendto(s, CUR_REQ.out_pkt, CUR_REQ.out_pktlen, 0,
144          (struct sockaddr *)&sin, addrlen);
145
146   cur_request_index = NEXT_INDEX(cur_request_index);
147 }
148
149 void get_request(struct msg *message)
150 {
151   static char packet[BUFSIZ];   /* Buffer for incoming packet */
152   int pktlen;                   /* Length of incoming packet */
153   int status = FAILURE;         /* Error status */
154
155   /* Sit around waiting for requests from the client. */
156   for (;;)
157     {
158       com_err(whoami, 0, "*** Ready for next request ***");
159       addrlen = sizeof(sin);
160       /* Receive a packet */
161       if ((pktlen = recvfrom(s, packet, sizeof(packet), 0,
162                              (struct sockaddr *)&sin, &addrlen)) < 0)
163         {
164           com_err(whoami, errno, " recvfrom");
165           /* Don't worry if error is interrupted system call. */
166           if (errno == EINTR)
167             continue;
168           exit(1);
169         }
170
171       /* Store available information */
172       CUR_REQ.seqno = 0;
173       CUR_REQ.ip_address = sin.sin_addr.s_addr;
174       CUR_REQ.cl_port = sin.sin_port;
175
176       /* Parse a request packet and save sequence number */
177       if ((status = parse_pkt(packet, pktlen, message)) != SUCCESS)
178         {
179           /* If error, format packet to send back to the client */
180           respond(status, NULL);
181         }
182       else
183         {
184           /* Check for retransmitted packet.  handle_retransmitted()
185              returns true if it handled a retransmitted packet. */
186           if (!handle_retransmitted())
187             break;
188         }
189     }
190 }
191
192 void report(int status, char *message)
193 {
194   respond(status, message);
195 }
196
197 /* This routine prepares a packet to send back to the client.  A
198    non-zero return status means that the client error message was
199    truncated. */
200 int format_pkt(char *packet, int *pktlenp, U_32BIT seqno,
201                int cl_status, char *message)
202 {
203   int len;                      /* Amount of message to send */
204   int status = SUCCESS;         /* Return status */
205
206   /* Convert byte order to network byte order */
207   U_32BIT vers = htonl((U_32BIT)CUR_UREG_VERSION);
208   cl_status = htonl((U_32BIT)cl_status);
209   /* Put current user registration protocol version into the packet */
210   memcpy(packet, &vers, sizeof(U_32BIT));
211   /* Put sequence number into the packet */
212   memcpy(packet + sizeof(U_32BIT), &seqno, sizeof(U_32BIT));
213   /* Put error status into the packet */
214   memcpy(packet + 2 * sizeof(U_32BIT), &cl_status, sizeof(U_32BIT));
215
216   /* Find out how much of the message to copy; truncate if too short. */
217   /* How much room is there left? */
218   len = *pktlenp - sizeof(U_32BIT) * 3;
219   if (!message)
220     message = "";
221   if (len < strlen(message) + 1) /* Room for null terminator */
222     {
223       status = FAILURE; /* Message was truncated */
224       /* Truncate the message */
225       message[len - 1] = '\0';
226     }
227
228   /* Copy the message into the packet */
229   strcpy(packet + 3 * sizeof(U_32BIT), message);
230   *pktlenp = 3 * sizeof(U_32BIT) + strlen(message);
231
232   return status;
233 }
234
235 /* The ureg_validate_char variable and routine were taken verbatim
236    out of server/qsupport.qc where they are called
237    validate_chars.  At some point, it may be desirable
238    to put this functionality in one place. */
239
240 /* ureg_validate_char: verify that there are no illegal characters in
241  * the string.  Legal characters are printing chars other than
242  * ", *, ?, \, [ and ].
243  */
244 static int illegalchars[] = {
245     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
246     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
247     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
248     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
249     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
250     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
251     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
252     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
253     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
254     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
255     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
256     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
258     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
259     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
260     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
261 };
262
263 int ureg_validate_char(char *s)
264 {
265   while (*s)
266     {
267       if (illegalchars[(int)*s++])
268         return FAILURE;
269     }
270   return SUCCESS;
271 }
272
273 /* This routine checks a packet and puts the information in it in
274    a structure if it is valid.  It also saves the sequence number
275    in the list of saved requests. */
276 int parse_pkt(char *packet, int pktlen, struct msg *message)
277 {
278   int status = SUCCESS; /* Error status */
279
280   com_err(whoami, 0, "Packet received");
281
282   if (pktlen < sizeof(U_32BIT))
283     status = UREG_BROKEN_PACKET;
284   if (status == SUCCESS)
285     {
286       /* Extract the user registration protocol version from the packet */
287       memcpy(&message->version, packet, sizeof(long));
288       /* Convert byte order from network to host */
289       message->version = ntohl(message->version);
290       /* Verify version */
291       if (message->version != CUR_UREG_VERSION)
292         status = UREG_WRONG_VERSION;
293     }
294
295   if (status == SUCCESS)
296     {
297       packet += sizeof(U_32BIT);
298       pktlen -= sizeof(U_32BIT);
299
300       if (pktlen < sizeof(U_32BIT))
301         status = UREG_BROKEN_PACKET;
302     }
303
304   if (status == SUCCESS)
305     {
306       /* Extract the sequence number from the packet */
307       memcpy(&CUR_REQ.seqno, packet, sizeof(long));
308
309       packet += sizeof(U_32BIT);
310       pktlen -= sizeof(U_32BIT);
311
312       if (pktlen < sizeof(U_32BIT))
313         status = UREG_BROKEN_PACKET;
314     }
315
316   if (status == SUCCESS)
317     {
318       /* Extract the request from the packet */
319       memcpy(&message->request, packet, sizeof(U_32BIT));
320       message->request = ntohl(message->request);
321       packet += sizeof(U_32BIT);
322       pktlen -= sizeof(U_32BIT);
323
324       /* Make sure that the packet contains only valid characters up
325          to the next null */
326       if (ureg_validate_char(packet) != SUCCESS)
327         {
328           com_err(whoami, 0, "Packet contains invalid characters.");
329           status = UREG_USER_NOT_FOUND;
330         }
331       else
332         {
333           /* Extract first name from the packet */
334           message->first = packet;
335
336           /* Scan forward until null appears in the packet or there
337              is no more packet! */
338           for (; *packet && pktlen > 0; --pktlen, ++packet)
339             continue;
340           if (pktlen <= 0)
341             status = UREG_BROKEN_PACKET;
342         }
343     }
344
345   if (status == SUCCESS)
346     {
347       /* Skip over the null */
348       packet++, pktlen--;
349
350       if (ureg_validate_char(packet) != SUCCESS)
351         {
352           com_err(whoami, 0, "Packet contains invalid characters.");
353           status = UREG_USER_NOT_FOUND;
354         }
355       else
356         {
357           /* Extract last name from the packet */
358           message->last = packet;
359
360           for (; *packet && pktlen > 0; --pktlen, ++packet)
361             continue;
362           if (pktlen <= 0)
363             status = UREG_BROKEN_PACKET;
364         }
365     }
366
367   if (status == SUCCESS)
368     {
369       packet++, pktlen--;
370
371       if (pktlen <= 0)
372         status = UREG_BROKEN_PACKET;
373     }
374
375   /* Extract encrypted information from packet */
376   message->encrypted = packet;
377   message->encrypted_len = pktlen;
378
379   if (status == SUCCESS)
380     {
381       com_err(whoami, status, "Request %d for %s %s", message->request,
382               message->first, message->last);
383     }
384   else
385     com_err(whoami, status, " - parse packet failed.");
386
387   return status;
388 }
389
390
391 u_long cur_req_sender(void)
392 {
393   return CUR_REQ.ip_address;
394 }
This page took 2.422517 seconds and 5 git commands to generate.