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