]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
Build without krb4 if it's unavailable.
[moira.git] / reg_svr / reg_svr.pc
CommitLineData
b50f996d 1/* $Id$
2 *
3 * Server for user registration with Moira and Kerberos.
4 *
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 */
9
10#include <mit-copyright.h>
11#include <moira.h>
12#include <mr_private.h>
13#include <moira_schema.h>
14#include <moira_site.h>
15#include "reg_svr.h"
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <sys/stat.h>
20#include <sys/time.h>
21#include <sys/utsname.h>
22
23#include <netinet/in.h>
24#include <netdb.h>
25
26#include <ctype.h>
27#include <errno.h>
28#include <signal.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <com_err.h>
cb974713 36#ifdef HAVE_KRB4
b50f996d 37#include <krb.h>
cb974713 38#endif
b50f996d 39
40EXEC SQL INCLUDE sqlca;
41
42RCSID("$Header$");
43
44char *whoami, *hostname, *shorthostname;
45
46char *find_usernames(char *first, char *middle, char *last);
276949c1 47int check_username_available(char *username);
b50f996d 48void fixname(char *name);
49int register_user(int uid, char *username);
50void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar);
51void sigshut(int);
52
53reg_client *cl = NULL;
54enum { RS_RUNNING, RS_SLEEPING, RS_EXITING } state = RS_RUNNING;
55
56int main(int argc, char **argv)
57{
58 int listener, nfds, i, clientid = 0;
59 fd_set readfds, xreadfds;
60 reg_client *clients;
61 int nclients, clientssize;
62 long status;
63 char *db = "moira";
64 struct utsname uts;
65 struct hostent *h;
66 struct sigaction sa;
67 struct stat st;
68
69 whoami = strrchr(argv[0], '/');
70 whoami = whoami ? whoami + 1 : argv[0];
71
72 set_com_err_hook(mr_com_err);
73
74 /* Read keys */
75 if (!read_rsa_key())
76 {
77 com_err(whoami, errno, "reading RSA key");
78 exit(1);
79 }
80 if (!read_hmac_key())
81 {
82 com_err(whoami, errno, "reading HMAC key");
83 exit(1);
84 }
85
86 /* Read error messages */
87 if (!read_errors())
88 {
89 com_err(whoami, errno, "reading error messages");
90 exit(1);
91 }
92
93 /* Connect to database */
94 EXEC SQL CONNECT :db IDENTIFIED BY :db;
95 if (sqlca.sqlcode)
96 {
97 char err_msg[256];
98 int bufsize = 256, msglength = 0;
99
100 sqlglm(err_msg, &bufsize, &msglength);
101 err_msg[msglength] = 0;
102 com_err(whoami, 0, "SQL error connecting to DBMS:\n%s", err_msg);
103 exit(1);
104 }
105
106 /* Get my hostname */
107 uname(&uts);
108 h = gethostbyname(uts.nodename);
109 if (!h)
110 {
111 com_err(whoami, 0, "Couldn't resolve hostname %s", uts.nodename);
112 exit(1);
113 }
114 hostname = lowercase(xstrdup(h->h_name));
115 shorthostname = xstrdup(hostname);
116 if (strchr(shorthostname, '.'))
117 *strchr(shorthostname, '.') = '\0';
118
119 /* Initialize kerberos */
120 status = init_kerberos();
121 if (status)
122 {
123 com_err(whoami, status, "initializing kerberos library");
124 exit(1);
125 }
126
127 /* Set up listening socket. */
128 listener = mr_listen("moira_ureg");
129 if (listener < 0)
130 {
131 com_err(whoami, errno, "couldn't create listening socket");
132 exit(1);
133 }
134 FD_ZERO(&xreadfds);
135 FD_SET(listener, &xreadfds);
136 nfds = listener + 1;
137
138 /* Initialize client array. */
139 nclients = 0;
140 clientssize = 5;
141 clients = malloc(clientssize * sizeof(reg_client));
142 if (!clients)
143 {
144 com_err(whoami, errno, "creating client array");
145 exit(1);
146 }
147
148 /* Set up signal handlers */
149 sa.sa_flags = 0;
150 sigemptyset(&sa.sa_mask);
151 sa.sa_handler = sigshut;
152 sigaction(SIGTERM, &sa, NULL);
153 sigaction(SIGINT, &sa, NULL);
154 sigaction(SIGHUP, &sa, NULL);
155 sa.sa_handler = SIG_IGN;
156 sigaction(SIGPIPE, &sa, NULL);
157
158 com_err(whoami, 0, "started (pid %d)", getpid());
159 com_err(whoami, 0, rcsid);
160
161 /* Main loop */
162 while (state != RS_EXITING)
163 {
164 if (state == RS_RUNNING && stat(MOIRA_MOTD_FILE, &st) == 0)
165 {
9dcee057 166 state = RS_SLEEPING;
b50f996d 167 com_err(whoami, 0, "found motd. reg_svr is sleeping");
168 }
169 else if (state == RS_SLEEPING && stat(MOIRA_MOTD_FILE, &st) == -1)
170 {
9dcee057 171 state = RS_RUNNING;
b50f996d 172 com_err(whoami, 0, "motd gone. reg_svr is running");
173 }
174
175 memcpy(&readfds, &xreadfds, sizeof(readfds));
176 if (select(nfds, &readfds, NULL, NULL, NULL) == -1)
177 {
178 if (errno != EINTR)
179 com_err(whoami, errno, "in select");
180 continue;
181 }
182
183 if (FD_ISSET(listener, &readfds))
184 {
185 int newconn, addrlen = sizeof(struct sockaddr_in);
186 struct sockaddr_in addr;
187
188 newconn = accept(listener, (struct sockaddr *)&addr, &addrlen);
189 if (newconn < 0)
190 com_err(whoami, errno, "accepting new connection");
191 else
192 {
193 nclients++;
194 if (nclients > clientssize)
195 {
196 clientssize = 2 * clientssize;
197 clients = xrealloc(clients, clientssize *
198 sizeof(reg_client));
199 }
200
201 cl = &clients[nclients - 1];
202 memset(cl, 0, sizeof(reg_client));
203 cl->fd = newconn;
204 cl->lastmod = time(NULL);
205 cl->clientid = ++clientid;
206 cl->random = init_rand(cl);
207 FD_SET(newconn, &xreadfds);
208 if (newconn >= nfds)
209 nfds = newconn + 1;
210
211 com_err(whoami, 0,
212 "New connection from %s port %d (now %d client%s)",
213 inet_ntoa(addr.sin_addr), (int)ntohs(addr.sin_port),
214 nclients, nclients != 1 ? "s" : "");
215 }
216 }
217
218 for (i = 0; i < nclients; i++)
219 {
220 cl = &clients[i];
221 if (FD_ISSET(cl->fd, &readfds))
222 {
223 cl->lastmod = time(NULL);
224 if (!cl->buf)
225 {
226 /* We're just starting */
227 cl->buf = malloc(3);
228 if (!cl->buf)
229 {
230 com_err(whoami, errno, "allocating read buffer");
231 reply(cl, INTERNAL_ERROR, "INIT", "c", NULL,
232 "Out of memory");
233 goto reap;
234 }
235 cl->nread = 0;
236 }
237
238 if (cl->nread < 3)
239 {
240 /* We haven't read the length byte yet... */
241 cl->nread += read(cl->fd, cl->buf + cl->nread,
242 3 - cl->nread);
243 if (cl->nread == 3)
244 {
245 cl->nmax = cl->buf[1] * 256 + cl->buf[2] + 3;
246 cl->buf = realloc(cl->buf, cl->nmax + 3);
247 if (!cl->buf)
248 {
249 com_err(whoami, errno, "reallocating read buffer");
250 reply(cl, INTERNAL_ERROR, "INIT", "c", NULL,
251 "Out of memory");
252 goto reap;
253 }
254 }
255 else if (cl->nread == 0)
256 {
257 /* client has closed connection. setting
258 lastmod will cause it to be reaped */
259 cl->lastmod = 0;
260 }
261 }
262 else
263 {
264 /* We know how long the packet is supposed to be */
265 cl->nread += read(cl->fd, cl->buf + cl->nread,
266 cl->nmax - cl->nread);
267 if (cl->nread == cl->nmax)
268 {
269 parse_packet(cl, cl->buf[0], cl->nread - 3, cl->buf + 3,
270 state == RS_SLEEPING);
271 free(cl->buf);
272 cl->buf = NULL;
273 }
274 }
275 }
276
277 reap:
278 if (cl->lastmod < time(NULL) - TIMEOUT)
279 {
280 com_err(whoami, 0, "Closed connection. (now %d client%s)",
281 nclients - 1, nclients != 2 ? "s" : "");
282 shutdown(cl->fd, 2);
283 close(cl->fd);
284 FD_CLR(cl->fd, &xreadfds);
285 free(cl->buf);
286 free(cl->id);
287 free(cl->username);
288 free(cl->suggestions);
289 free(cl->random);
290 clients[i] = clients[--nclients];
291 i--;
292 }
293 }
294 cl = NULL;
295 }
296 com_err(whoami, 0, "Exiting.");
297}
298
299void RIFO(reg_client *rc, int argc, char **argv)
300{
301 EXEC SQL BEGIN DECLARE SECTION;
302 char *ufirst, *umiddle, *ulast, *id;
303 char login[USERS_LOGIN_SIZE], first[USERS_FIRST_SIZE];
304 char middle[USERS_MIDDLE_SIZE], last[USERS_LAST_SIZE];
305 char fullname[USERS_FIRST_SIZE + USERS_MIDDLE_SIZE + USERS_LAST_SIZE];
ee47c73a 306 char class[USERS_TYPE_SIZE], pin[USERS_PIN_SIZE];
1dc2ec48 307 int uid, status, secure, sqlstatus, count;
b50f996d 308 EXEC SQL END DECLARE SECTION;
309
310 if (rc->uid || argc != 4)
311 {
312 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
313 return;
314 }
315
316 ufirst = argv[0];
317 umiddle = argv[1];
318 ulast = argv[2];
319 id = argv[3];
320
1dc2ec48 321 EXEC SQL SELECT count(login) INTO :count FROM users WHERE clearid = :id;
322
b50f996d 323 /* "ORDER BY status" so that if there's both a matching state 0 entry
324 and a matching state 3 entry, we'll get the former. */
325 EXEC SQL DECLARE csr_id CURSOR FOR
ee47c73a 326 SELECT login, unix_uid, status, secure, pin, first, middle, last, type
b50f996d 327 FROM users WHERE clearid = :id ORDER BY status;
328 EXEC SQL OPEN csr_id;
329 while (1)
330 {
331 EXEC SQL FETCH csr_id INTO :login, :uid, :status,
ee47c73a 332 :secure, :pin, :first, :middle, :last, :class;
b50f996d 333 if (sqlca.sqlcode)
334 break;
335 strtrim(login);
336 strtrim(first);
337 strtrim(middle);
338 strtrim(last);
339 strtrim(class);
ee47c73a 340 strtrim(pin);
b50f996d 341
1dc2ec48 342 /* It's possible they have both a deleted account and a status 8
343 * account. We can't compensate for that in the ORDER BY clause
344 * above, so check here. If they have more than one entry and the
345 * first one we get is deleted, skip it.
346 */
347 if (status == US_DELETED && count > 1)
348 continue;
349
b50f996d 350 /* Check names, allowing for the possibility that Moira and the
351 user might have them split up differently. eg, Mary/Ann/Singleton
352 vs. Mary Ann/Singleton. */
353 if (strcasecmp(last, ulast) && strncasecmp(last, ulast, strlen(last)) &&
354 strncasecmp(last, ulast, strlen(ulast)))
355 continue;
356 if (strlen(last) > 3 && strlen(ulast) < 3)
357 continue;
358 if (strcasecmp(first, ufirst) &&
359 strncasecmp(first, ufirst, strlen(first)) &&
360 strncasecmp(first, ufirst, strlen(ufirst)))
361 continue;
362 if (strlen(first) > 3 && strlen(ufirst) < 3)
363 continue;
ba41d432 364 if (!*ufirst && !*ulast)
365 continue;
366
b50f996d 367 /* Ignore the middle name since Moira doesn't have those reliably */
368 break;
369 }
370 sqlstatus = sqlca.sqlcode;
371 EXEC SQL CLOSE csr_id;
372
373 if (sqlstatus)
374 {
375 reply(rc, NOT_FOUND_IN_DATABASE, "GETN", "d", NULL);
376 return;
377 }
378
379 switch (status)
380 {
381 case US_REGISTERED:
382 case US_ENROLLED:
383 case US_ENROLL_NOT_ALLOWED:
9d5ca0f4 384 case US_REGISTERED_KERBEROS_ONLY:
b50f996d 385 reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
386 return;
387
388 case US_DELETED:
389 reply(rc, ACCOUNT_DELETED, "INIT", "c", NULL, login);
390 return;
391
392 case US_NOT_ALLOWED:
393 reply(rc, NOT_ELIGIBLE, "INIT", "c", NULL);
394 return;
395
396 default:
397 break;
398 }
399
9d5ca0f4 400 rc->user_status = status;
b50f996d 401 rc->uid = uid;
402 sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
403 if (!strcmp(class, "MITS"))
404 strcpy(class, "STAFF");
405 if (secure == 1)
406 {
407 rc->id = strdup(id);
408 if (!rc->id)
409 {
410 com_err(whoami, errno, "in RIFO");
411 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
412 return;
413 }
414 }
415 if (*login != '#')
416 {
417 rc->reserved_username = 1;
418 rc->username = strdup(login);
419 if (!rc->username)
420 {
421 com_err(whoami, errno, "in RIFO");
422 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
423 return;
424 }
425 }
426 else
427 {
428 rc->suggestions = find_usernames(first, middle, last);
8dc13a24 429 if (!rc->suggestions && errno)
b50f996d 430 {
431 com_err(whoami, errno, "in RIFO");
8dc13a24 432 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
b50f996d 433 return;
434 }
435 }
436
437 if (rc->id)
ee47c73a 438 {
439 if (*pin != '\0')
440 reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
441 else
442 reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
443 }
b50f996d 444 else if (!rc->username)
445 reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
446 else
78b14dbc 447 {
9d5ca0f4 448 if (rc->user_status == US_NO_LOGIN_YET ||
449 rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
78b14dbc 450 {
451 status = check_kerberos(login);
9d5ca0f4 452 if (status == MR_SUCCESS &&
453 rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
454 status = register_user(rc->uid, login);
78b14dbc 455 if (status == MR_IN_USE)
456 {
457 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
458 rc->username);
459 return;
460 }
461 else if (status == MR_DOWN)
462 {
463 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
464 return;
465 }
466 else if (status != MR_SUCCESS)
467 {
468 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
469 error_message(status));
470 return;
471 }
472 }
473 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
474 }
b50f996d 475}
476
477void SWRD(reg_client *rc, int argc, char **argv)
478{
479 char *words[6];
480 int i;
481
482 if (!rc->id || argc != 6)
483 {
484 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
485 return;
486 }
487
488 getwordlist(rc->id, words);
489 for (i = 0; i < 6; i++)
490 {
491 if (strcasecmp(strtrim(argv[i]), words[i]))
492 break;
493 }
494 if (i != 6)
495 {
496 reply(rc, BAD_SIX_WORDS, "GETW", "d", NULL);
497 return;
498 }
499
500 free(rc->id);
501 rc->id = NULL;
502 if (!rc->username)
503 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
504 else
505 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
506}
507
ee47c73a 508void SPIN(reg_client *rc, int argc, char **argv)
509{
510 EXEC SQL BEGIN DECLARE SECTION;
511 char pin[USERS_PIN_SIZE];
512 EXEC SQL END DECLARE SECTION;
513
514 if (!rc->id || argc != 1)
515 {
516 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
517 return;
518 }
519
483aa0a7 520 EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id
1dc2ec48 521 AND status = :rc->user_status;
ee47c73a 522 strtrim(pin);
523 if (strcmp(argv[0], pin) != 0)
524 {
525 reply(rc, BAD_PIN, "GETI", "d", NULL);
526 return;
527 }
528
529 free(rc->id);
530 rc->id = NULL;
531 if (!rc->username)
532 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
533 else
d10e2ed1 534 {
535 register_user(rc->uid, rc->username);
536 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
537 }
ee47c73a 538}
539
276949c1 540void CLGN(reg_client *rc, int argc, char **argv)
541{
542 int i;
543 char *login;
544 long status;
545
546 if (!rc->uid || rc->id || rc->username || argc != 1)
547 {
548 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
549 return;
550 }
551
552 login = argv[0];
553
554 /* make sure someone's not trying to overrun reply */
555 if (strlen(login) > 100)
556 {
557 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
558 rc->lastmod = 0;
559 return;
560 }
561
562 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
563 (login[0] == '_') || isdigit(login[0]))
564 {
565 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
566 3, USERS_LOGIN_SIZE - 1);
567 return;
568 }
569
570 for (i = 0; i < strlen(login); i++)
571 {
572 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
573 {
574 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
575 3, USERS_LOGIN_SIZE - 1);
576 return;
577 }
578 }
579
580 status = check_kerberos(login);
581 if (status == MR_SUCCESS)
582 {
583 status = check_username_available(login);
584 if (status == MR_SUCCESS)
585 {
586 reply(rc, USERNAME_AVAILABLE, "LOGC", "c", login, login);
587 return;
588 }
589 }
590
591 if (status == MR_IN_USE)
592 {
593 if (rc->reserved_username)
594 {
595 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
596 rc->username);
597 return;
598 }
599 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
600 return;
601 }
602 else if (status == MR_DOWN)
603 {
604 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
605 return;
606 }
607 else if (status != MR_SUCCESS)
608 {
609 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
610 return;
611 }
612}
613
b50f996d 614void LOGN(reg_client *rc, int argc, char **argv)
615{
616 int i;
617 char *login;
618 long status;
619
620 if (!rc->uid || rc->id || rc->username || argc != 1)
621 {
622 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
623 return;
624 }
625
626 login = argv[0];
627
628 /* make sure someone's not trying to overrun reply */
629 if (strlen(login) > 100)
630 {
631 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
632 rc->lastmod = 0;
633 return;
634 }
635
636 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
637 (login[0] == '_') || isdigit(login[0]))
638 {
639 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
640 3, USERS_LOGIN_SIZE - 1);
641 return;
642 }
643
644 for (i = 0; i < strlen(login); i++)
645 {
646 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
647 {
648 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
649 3, USERS_LOGIN_SIZE - 1);
650 return;
651 }
652 }
653
654 status = check_kerberos(login);
655 if (status == MR_SUCCESS)
9d5ca0f4 656 {
657 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
658 EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
659 else
660 status = register_user(rc->uid, login);
661 }
b50f996d 662 if (status == MR_IN_USE)
663 {
664 if (rc->reserved_username)
665 {
666 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
667 rc->username);
668 return;
669 }
670 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
671 return;
672 }
673 else if (status == MR_DOWN)
674 {
675 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
676 return;
677 }
678 else if (status != MR_SUCCESS)
679 {
680 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
681 return;
682 }
683
684 rc->username = strdup(login);
685 if (!rc->username)
686 {
687 com_err(whoami, errno, "in LOGN");
688 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
689 return;
690 }
691 reply(rc, USERNAME_OK, "GETP", "c", NULL, login);
692}
693
694int ctypes[256] = {
695 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ - ^O */
696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^P - ^_ */
697 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* SPACE - / */
698 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, /* 0 - ? */
699 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* : - O */
700 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, /* P - _ */
701 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* ` - o */
702 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, /* p - ^? */
703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
704 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
705 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
706 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
707 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
708 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
709 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
710 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
711};
712
713void PSWD(reg_client *rc, int argc, char **argv)
714{
715 long status;
716 char *password = argv[0], *p;
717 EXEC SQL BEGIN DECLARE SECTION;
718 char *login = rc->username;
719 EXEC SQL END DECLARE SECTION;
720
721 if (!rc->username || rc->id || argc != 1)
722 {
723 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
724 return;
725 }
726
727 /* password quality checking */
728 if (strlen(password) < 4)
729 {
730 reply(rc, PASSWORD_SHORT, "GETP", "c", NULL);
731 return;
732 }
733
734 if (strlen(password) < 7)
735 {
736 for (p = password + 1; *p; p++)
737 {
738 if (ctypes[*p] != ctypes[*(p - 1)])
739 break;
740 }
741 if (!*p)
742 {
743 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
744 return;
745 }
746 }
747
748 if (!strcasecmp(password, "GykoR-66") ||
749 !strcasecmp(password, "slaRooBey") ||
750 !strcasecmp(password, "krang-its") ||
751 !strcasecmp(password, "2HotPeetzas") ||
752 !strcasecmp(password, "ItzAGurl"))
753 {
754 reply(rc, PASSWORD_SAMPLE, "GETP", "c", NULL);
755 return;
756 }
757
758 status = register_kerberos(rc->username, password);
9c0c1480 759 if (status == MR_QUALITY)
760 {
761 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
762 return;
763 }
764 else if (status == MR_IN_USE)
b50f996d 765 {
766 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
767 rc->username);
768 return;
769 }
770 else if (status)
771 {
772 com_err(whoami, status, "registering username with Kerberos");
773 reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
774 return;
775 }
9d5ca0f4 776
777 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
778 EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
779 else
780 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
b50f996d 781 EXEC SQL COMMIT;
782
783 reply(rc, DONE, "INIT", "c", NULL, rc->username);
784}
785
786void QUIT(reg_client *rc, int argc, char **argv)
787{
788}
789
790/* Register a user in Moira */
791int register_user(int uid, char *username)
792{
93ab973b 793 EXEC SQL BEGIN DECLARE SECTION;
bc06d5e3 794 char class[USERS_TYPE_SIZE];
93ab973b 795 EXEC SQL END DECLARE SECTION;
b50f996d 796 char uidbuf[10], *qargv[3], *motd = NULL;
797 long status;
798
799 status = mr_connect(hostname);
800 if (status)
801 return status;
802
803 status = mr_motd(&motd);
804 if (status || motd)
805 {
806 mr_disconnect();
807 return MR_DOWN;
808 }
809
cb974713 810 status = mr_krb5_auth("reg_svr");
b50f996d 811 if (status)
812 {
813 com_err(whoami, status, "authenticating to moira");
814 mr_disconnect();
815 return MR_INTERNAL;
816 }
817
bc06d5e3 818 EXEC SQL SELECT type INTO :class FROM users WHERE unix_uid = :uid;
93ab973b 819
b50f996d 820 sprintf(uidbuf, "%d", uid);
821 qargv[0] = uidbuf;
822 qargv[1] = username;
93ab973b 823
bc06d5e3 824 /* Incoming students should be given Exchange poboxes.
825 * Doesn't work for undergrads in the class of 2100 or higher.
93ab973b 826 */
bc06d5e3 827 if (!strcmp(strtrim(class), "G") || !strncmp(class, "FALL", 4) ||
828 !strncmp(class, "SPRING", 5) || !strncmp(class, "SUMMER", 6) ||
829 !strncmp(class, "20", 2))
830 {
831 com_err(whoami, 0, "assigning EXCHANGE pobox to user %s, class %s", username, class);
93ab973b 832 qargv[2] = "EXCHANGE";
bc06d5e3 833 }
93ab973b 834 else
bc06d5e3 835 {
836 com_err(whoami, 0, "assigning IMAP pobox to user %s, class %s", username, class);
837 qargv[2] = "IMAP";
838 }
93ab973b 839
b50f996d 840 status = mr_query("register_user", 3, qargv, NULL, NULL);
841 mr_disconnect();
842 return status;
843}
844
845
846/* Find some typical available usernames */
847
848char *uname_patterns[] = {
849 "FL", /* johndoe */
850 "fmllllll", /* jmdoe... (last name truncated) */
851 "flllllll", /* jdoe.... ("") */
852 "llllllll", /* doe..... ("") */
853 "fml", /* jmd */
854 "Fl", /* johnd */
855 "Lf", /* doej */
856 "Lfm", /* doejm */
857 "F", /* john */
858};
859int num_patterns = sizeof(uname_patterns) / sizeof(char *);
860
861char *find_usernames(char *first, char *middle, char *last)
862{
863 EXEC SQL BEGIN DECLARE SECTION;
864 char username[2 * USERS_LOGIN_SIZE];
865 int count;
866 EXEC SQL END DECLARE SECTION;
867 int pat, len;
868 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
869
870 fixname(first);
871 fixname(middle);
872 fixname(last);
873
874 for (pat = 0; pat < num_patterns; pat++)
875 {
876 up = username;
877 fp = first;
878 mp = middle;
879 lp = last;
880 for (pp = uname_patterns[pat]; *pp; pp++)
881 {
882 switch (*pp)
883 {
884 case 'f':
885 if (*fp)
886 *up++ = *fp++;
887 break;
888
889 case 'F':
890 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
891 up += sprintf(up, "%s", first);
892 else
893 goto nextpattern;
894 break;
895
896 case 'm':
897 if (!*middle)
898 goto nextpattern;
899 if (*mp)
900 *up++ = *mp++;
901 break;
902
903 case 'l':
904 if (*lp)
905 *up++ = *lp++;
906 break;
907
908 case 'L':
909 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
910 up += sprintf(up, "%s", last);
911 else
912 goto nextpattern;
913 break;
914 }
915 }
916 *up = '\0';
917
d1d04a6c 918 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 919 continue;
920
921 EXEC SQL SELECT COUNT(login) INTO :count FROM users
922 WHERE login = :username;
923 if (sqlca.sqlcode)
8dc13a24 924 {
925 errno = MR_DBMS_ERR;
926 return NULL;
927 }
b50f996d 928 if (count == 0)
929 {
930 EXEC SQL SELECT COUNT(name) INTO :count FROM list
931 WHERE name = :username;
932 if (sqlca.sqlcode)
8dc13a24 933 {
934 errno = MR_DBMS_ERR;
935 return NULL;
936 }
b50f996d 937 }
938 if (count == 0)
939 {
940 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
941 WHERE label = :username;
942 if (sqlca.sqlcode)
8dc13a24 943 {
944 errno = MR_DBMS_ERR;
945 return NULL;
946 }
b50f996d 947 }
948
949 if (count == 0)
950 {
951 if (unames)
952 {
953 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
954 if (!unames)
955 return NULL;
956 strcat(unames, ", ");
957 strcat(unames, username);
958 }
959 else
960 {
961 unames = strdup(username);
962 if (!unames)
963 return NULL;
964 }
965 }
966
967 nextpattern:
968 ;
969 }
970
8dc13a24 971 /* unames will be NULL if we couldn't suggest a username. Clear
972 errno so the caller can distinguish this from an error case. */
973 errno = 0;
b50f996d 974 return unames;
975}
976
276949c1 977/* This does the database-side checks to make sure a username is
978 * available.
979 */
980int check_username_available(char *username)
981{
982 int count;
983
984 EXEC SQL SELECT COUNT(login) INTO :count FROM users
985 WHERE login = :username;
986 if (sqlca.sqlcode)
987 return MR_DBMS_ERR;
988 if (count != 0)
989 return MR_IN_USE;
990
991 EXEC SQL SELECT COUNT(name) INTO :count FROM list
992 WHERE name = :username;
993 if (sqlca.sqlcode)
994 return MR_DBMS_ERR;
995 if (count != 0)
996 return MR_IN_USE;
997
998 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
999 WHERE label = :username;
1000 if (sqlca.sqlcode)
1001 return MR_DBMS_ERR;
1002 if (count != 0)
1003 return MR_IN_USE;
1004
4da47473 1005 EXEC SQL SELECT COUNT(login) INTO :count FROM userhistory
1006 WHERE login = :username;
1007 if (sqlca.sqlcode)
1008 return MR_DBMS_ERR;
1009 if (count != 0)
1010 return MR_IN_USE;
1011
276949c1 1012 return MR_SUCCESS;
1013}
1014
b50f996d 1015void fixname(char *name)
1016{
1017 char *s, *d;
1018
1019 for (s = d = name; *s; s++)
1020 {
1021 if (isalnum(*s))
1022 *d++ = tolower(*s);
1023 }
1024 *d = '\0';
1025}
1026
1027void *xmalloc(size_t bytes)
1028{
1029 void *buf = malloc(bytes);
1030
1031 if (buf)
1032 return buf;
1033
1034 com_err(whoami, errno, "in xmalloc");
1035 exit(1);
1036}
1037
1038void *xrealloc(void *ptr, size_t bytes)
1039{
1040 void *buf = realloc(ptr, bytes);
1041
1042 if (buf)
1043 return buf;
1044
1045 com_err(whoami, errno, "in xrealloc");
1046 exit(1);
1047}
1048
1049char *xstrdup(char *str)
1050{
1051 char *buf = strdup(str);
1052
1053 if (buf)
1054 return buf;
1055
1056 com_err(whoami, errno, "in xstrdup");
1057 exit(1);
1058}
1059
1060void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
1061{
1062 if (whoami)
1063 {
1064 fputs(whoami, stderr);
1065 if (cl)
1066 fprintf(stderr, "[#%d]", cl->clientid);
1067 fputs(": ", stderr);
1068 }
1069 if (code) {
1070 fputs(error_message(code), stderr);
1071 fputs(" ", stderr);
1072 }
1073 if (fmt)
1074 vfprintf(stderr, fmt, pvar);
1075 putc('\n', stderr);
1076}
1077
1078void sigshut(int sig)
1079{
1080 state = RS_EXITING;
1081}
This page took 0.218825 seconds and 5 git commands to generate.