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