]>
Commit | Line | Data |
---|---|---|
7ac48069 | 1 | /* $Id$ |
9a83b251 | 2 | * |
7ac48069 | 3 | * Server for user registration with Moira and Kerberos. |
9a83b251 | 4 | * |
7ac48069 | 5 | * This file handles the processing of requests for the register |
6 | * server. | |
9a83b251 | 7 | * |
7ac48069 | 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>. | |
9a83b251 | 11 | */ |
12 | ||
0a5ff702 | 13 | #include <mit-copyright.h> |
7ac48069 | 14 | #include <moira.h> |
15 | #include <moira_site.h> | |
16 | ||
952aa193 | 17 | #include <sys/types.h> |
9a83b251 | 18 | #include <sys/socket.h> |
7ac48069 | 19 | |
9a83b251 | 20 | #include <netinet/in.h> |
7ac48069 | 21 | #include <arpa/inet.h> |
9a83b251 | 22 | #include <netdb.h> |
7ac48069 | 23 | |
24 | #include <errno.h> | |
25 | #include <stdio.h> | |
26 | #include <string.h> | |
27 | ||
952aa193 | 28 | #include "reg_svr.h" |
9a83b251 | 29 | |
7ac48069 | 30 | RCSID("$Header$"); |
31 | ||
9a83b251 | 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) | |
5eaef520 | 36 | |
9a83b251 | 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) */ | |
5eaef520 | 41 | |
42 | /* In order to elegantly handle multiple retransmissions, an instance | |
9a83b251 | 43 | of this structure will be retained for the last NUM_REQUESTS_SAVED |
44 | transactions with the client. */ | |
45 | struct request_save { | |
5eaef520 | 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 */ | |
9a83b251 | 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 | ||
7ac48069 | 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 | ||
5eaef520 | 68 | void clear_req(struct request_save *req) |
9a83b251 | 69 | { |
5eaef520 | 70 | req->seqno = 0; |
71 | req->ip_address = 0; | |
72 | req->cl_port = 0; | |
9a83b251 | 73 | } |
74 | ||
5eaef520 | 75 | void req_initialize(void) |
9a83b251 | 76 | { |
44d12d58 | 77 | int i; |
9a83b251 | 78 | |
5eaef520 | 79 | /* Get service information from /etc/services */ |
59ec8dae | 80 | if (!(sp = getservbyname("moira_ureg", "udp"))) |
9a83b251 | 81 | { |
59ec8dae | 82 | com_err(whoami, errno, " unknown service moira_ureg/udp"); |
5eaef520 | 83 | exit(1); |
9a83b251 | 84 | } |
5eaef520 | 85 | |
86 | /* Get an internet style datagram socket */ | |
87 | if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) | |
9a83b251 | 88 | { |
5eaef520 | 89 | com_err(whoami, errno, " socket"); |
90 | exit(1); | |
9a83b251 | 91 | } |
5eaef520 | 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) | |
9a83b251 | 100 | { |
5eaef520 | 101 | com_err(whoami, errno, " bind"); |
102 | exit(1); | |
9a83b251 | 103 | } |
104 | ||
5eaef520 | 105 | for (i = 0; i < NUM_REQUESTS_SAVED; i++) |
106 | clear_req(&(requests[i])); | |
107 | } | |
9a83b251 | 108 | |
5eaef520 | 109 | int handle_retransmitted(void) |
9a83b251 | 110 | { |
44d12d58 | 111 | int i; /* A counter */ |
5eaef520 | 112 | int status = FALSE; /* Return status */ |
113 | ||
114 | for (i = PREV_INDEX(cur_request_index); i != cur_request_index; | |
115 | i = PREV_INDEX(i)) | |
9a83b251 | 116 | { |
5eaef520 | 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 */ | |
9a83b251 | 121 | { |
5eaef520 | 122 | status = TRUE; |
123 | sendto(s, requests[i].out_pkt, requests[i].out_pktlen, | |
124 | 0, (struct sockaddr *)&sin, addrlen); | |
125 | break; | |
9a83b251 | 126 | } |
127 | } | |
128 | ||
5eaef520 | 129 | return status; |
9a83b251 | 130 | } |
131 | ||
5eaef520 | 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) | |
9a83b251 | 137 | { |
5eaef520 | 138 | CUR_REQ.out_pktlen = sizeof(CUR_REQ.out_pkt); |
9a83b251 | 139 | |
5eaef520 | 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); | |
9a83b251 | 145 | |
5eaef520 | 146 | cur_request_index = NEXT_INDEX(cur_request_index); |
9a83b251 | 147 | } |
148 | ||
5eaef520 | 149 | void get_request(struct msg *message) |
9a83b251 | 150 | { |
5eaef520 | 151 | static char packet[BUFSIZ]; /* Buffer for incoming packet */ |
152 | int pktlen; /* Length of incoming packet */ | |
153 | int status = FAILURE; /* Error status */ | |
9a83b251 | 154 | |
5eaef520 | 155 | /* Sit around waiting for requests from the client. */ |
156 | for (;;) | |
9a83b251 | 157 | { |
5eaef520 | 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) | |
9a83b251 | 163 | { |
5eaef520 | 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); | |
9a83b251 | 169 | } |
5eaef520 | 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) | |
9a83b251 | 178 | { |
5eaef520 | 179 | /* If error, format packet to send back to the client */ |
180 | respond(status, NULL); | |
9a83b251 | 181 | } |
5eaef520 | 182 | else |
9a83b251 | 183 | { |
5eaef520 | 184 | /* Check for retransmitted packet. handle_retransmitted() |
185 | returns true if it handled a retransmitted packet. */ | |
186 | if (!handle_retransmitted()) | |
187 | break; | |
9a83b251 | 188 | } |
189 | } | |
190 | } | |
191 | ||
5eaef520 | 192 | void report(int status, char *message) |
9a83b251 | 193 | { |
5eaef520 | 194 | respond(status, message); |
9a83b251 | 195 | } |
196 | ||
5eaef520 | 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) | |
9a83b251 | 202 | { |
5eaef520 | 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 */ | |
9a83b251 | 222 | { |
5eaef520 | 223 | status = FAILURE; /* Message was truncated */ |
224 | /* Truncate the message */ | |
225 | message[len - 1] = '\0'; | |
9a83b251 | 226 | } |
227 | ||
5eaef520 | 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; | |
9a83b251 | 233 | } |
234 | ||
5eaef520 | 235 | /* The ureg_validate_char variable and routine were taken verbatim |
9a83b251 | 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 | |
5eaef520 | 241 | * the string. Legal characters are printing chars other than |
9a83b251 | 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 | ||
44d12d58 | 263 | int ureg_validate_char(char *s) |
9a83b251 | 264 | { |
5eaef520 | 265 | while (*s) |
266 | { | |
7ac48069 | 267 | if (illegalchars[(int)*s++]) |
5eaef520 | 268 | return FAILURE; |
269 | } | |
270 | return SUCCESS; | |
9a83b251 | 271 | } |
272 | ||
5eaef520 | 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) | |
9a83b251 | 277 | { |
5eaef520 | 278 | int status = SUCCESS; /* Error status */ |
9a83b251 | 279 | |
5eaef520 | 280 | com_err(whoami, 0, "Packet received"); |
9a83b251 | 281 | |
5eaef520 | 282 | if (pktlen < sizeof(U_32BIT)) |
283 | status = UREG_BROKEN_PACKET; | |
284 | if (status == SUCCESS) | |
9a83b251 | 285 | { |
5eaef520 | 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; | |
9a83b251 | 293 | } |
294 | ||
5eaef520 | 295 | if (status == SUCCESS) |
9a83b251 | 296 | { |
5eaef520 | 297 | packet += sizeof(U_32BIT); |
298 | pktlen -= sizeof(U_32BIT); | |
299 | ||
300 | if (pktlen < sizeof(U_32BIT)) | |
301 | status = UREG_BROKEN_PACKET; | |
9a83b251 | 302 | } |
303 | ||
5eaef520 | 304 | if (status == SUCCESS) |
9a83b251 | 305 | { |
5eaef520 | 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; | |
9a83b251 | 314 | } |
315 | ||
5eaef520 | 316 | if (status == SUCCESS) |
9a83b251 | 317 | { |
5eaef520 | 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) | |
9a83b251 | 327 | { |
5eaef520 | 328 | com_err(whoami, 0, "Packet contains invalid characters."); |
329 | status = UREG_USER_NOT_FOUND; | |
9a83b251 | 330 | } |
5eaef520 | 331 | else |
9a83b251 | 332 | { |
5eaef520 | 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; | |
9a83b251 | 342 | } |
343 | } | |
5eaef520 | 344 | |
345 | if (status == SUCCESS) | |
9a83b251 | 346 | { |
5eaef520 | 347 | /* Skip over the null */ |
348 | packet++, pktlen--; | |
349 | ||
350 | if (ureg_validate_char(packet) != SUCCESS) | |
9a83b251 | 351 | { |
5eaef520 | 352 | com_err(whoami, 0, "Packet contains invalid characters."); |
353 | status = UREG_USER_NOT_FOUND; | |
9a83b251 | 354 | } |
5eaef520 | 355 | else |
9a83b251 | 356 | { |
5eaef520 | 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; | |
9a83b251 | 364 | } |
365 | } | |
366 | ||
5eaef520 | 367 | if (status == SUCCESS) |
9a83b251 | 368 | { |
5eaef520 | 369 | packet++, pktlen--; |
370 | ||
371 | if (pktlen <= 0) | |
372 | status = UREG_BROKEN_PACKET; | |
9a83b251 | 373 | } |
374 | ||
5eaef520 | 375 | /* Extract encrypted information from packet */ |
376 | message->encrypted = packet; | |
377 | message->encrypted_len = pktlen; | |
378 | ||
379 | if (status == SUCCESS) | |
9a83b251 | 380 | { |
5eaef520 | 381 | com_err(whoami, status, "Request %d for %s %s", message->request, |
382 | message->first, message->last); | |
9a83b251 | 383 | } |
5eaef520 | 384 | else |
385 | com_err(whoami, status, " - parse packet failed."); | |
9a83b251 | 386 | |
5eaef520 | 387 | return status; |
9a83b251 | 388 | } |
f3835da8 | 389 | |
390 | ||
5eaef520 | 391 | u_long cur_req_sender(void) |
f3835da8 | 392 | { |
5eaef520 | 393 | return CUR_REQ.ip_address; |
f3835da8 | 394 | } |