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