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