]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
If a user has the secure bit set and a PIN defined in the database, ask
[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];
6531b2d6 304 int uid, status, secure, sqlstatus, string_id;
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
318 /* "ORDER BY status" so that if there's both a matching state 0 entry
319 and a matching state 3 entry, we'll get the former. */
320 EXEC SQL DECLARE csr_id CURSOR FOR
ee47c73a 321 SELECT login, unix_uid, status, secure, pin, first, middle, last, type
b50f996d 322 FROM users WHERE clearid = :id ORDER BY status;
323 EXEC SQL OPEN csr_id;
324 while (1)
325 {
326 EXEC SQL FETCH csr_id INTO :login, :uid, :status,
ee47c73a 327 :secure, :pin, :first, :middle, :last, :class;
b50f996d 328 if (sqlca.sqlcode)
329 break;
330 strtrim(login);
331 strtrim(first);
332 strtrim(middle);
333 strtrim(last);
334 strtrim(class);
ee47c73a 335 strtrim(pin);
b50f996d 336
337 /* Check names, allowing for the possibility that Moira and the
338 user might have them split up differently. eg, Mary/Ann/Singleton
339 vs. Mary Ann/Singleton. */
340 if (strcasecmp(last, ulast) && strncasecmp(last, ulast, strlen(last)) &&
341 strncasecmp(last, ulast, strlen(ulast)))
342 continue;
343 if (strlen(last) > 3 && strlen(ulast) < 3)
344 continue;
345 if (strcasecmp(first, ufirst) &&
346 strncasecmp(first, ufirst, strlen(first)) &&
347 strncasecmp(first, ufirst, strlen(ufirst)))
348 continue;
349 if (strlen(first) > 3 && strlen(ufirst) < 3)
350 continue;
351 /* Ignore the middle name since Moira doesn't have those reliably */
352 break;
353 }
354 sqlstatus = sqlca.sqlcode;
355 EXEC SQL CLOSE csr_id;
356
357 if (sqlstatus)
358 {
359 reply(rc, NOT_FOUND_IN_DATABASE, "GETN", "d", NULL);
360 return;
361 }
362
363 switch (status)
364 {
365 case US_REGISTERED:
366 case US_ENROLLED:
367 case US_ENROLL_NOT_ALLOWED:
368 reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
369 return;
370
371 case US_DELETED:
372 reply(rc, ACCOUNT_DELETED, "INIT", "c", NULL, login);
373 return;
374
375 case US_NOT_ALLOWED:
376 reply(rc, NOT_ELIGIBLE, "INIT", "c", NULL);
377 return;
378
379 default:
380 break;
381 }
382
383 rc->uid = uid;
384 sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
385 if (!strcmp(class, "MITS"))
386 strcpy(class, "STAFF");
387 if (secure == 1)
388 {
389 rc->id = strdup(id);
390 if (!rc->id)
391 {
392 com_err(whoami, errno, "in RIFO");
393 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
394 return;
395 }
396 }
397 if (*login != '#')
398 {
399 rc->reserved_username = 1;
400 rc->username = strdup(login);
401 if (!rc->username)
402 {
403 com_err(whoami, errno, "in RIFO");
404 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
405 return;
406 }
407 }
408 else
409 {
410 rc->suggestions = find_usernames(first, middle, last);
8dc13a24 411 if (!rc->suggestions && errno)
b50f996d 412 {
413 com_err(whoami, errno, "in RIFO");
8dc13a24 414 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
b50f996d 415 return;
416 }
417 }
418
419 if (rc->id)
ee47c73a 420 {
421 if (*pin != '\0')
422 reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
423 else
424 reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
425 }
b50f996d 426 else if (!rc->username)
427 reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
428 else
78b14dbc 429 {
430 if (status == US_NO_LOGIN_YET)
431 {
432 status = check_kerberos(login);
433 if (status == MR_SUCCESS)
6531b2d6 434 if (!strcmp(class, "LINCOLN"))
435 {
436 EXEC SQL SELECT string_id INTO :string_id FROM strings
437 WHERE string = 'LINCOLN: no pobox or filesys';
438 EXEC SQL UPDATE users SET comments = :string_id
439 WHERE login = :login;
440 }
441 else
442 status = register_user(rc->uid, login);
78b14dbc 443 if (status == MR_IN_USE)
444 {
445 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
446 rc->username);
447 return;
448 }
449 else if (status == MR_DOWN)
450 {
451 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
452 return;
453 }
454 else if (status != MR_SUCCESS)
455 {
456 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
457 error_message(status));
458 return;
459 }
460 }
461 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
462 }
b50f996d 463}
464
465void SWRD(reg_client *rc, int argc, char **argv)
466{
467 char *words[6];
468 int i;
469
470 if (!rc->id || argc != 6)
471 {
472 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
473 return;
474 }
475
476 getwordlist(rc->id, words);
477 for (i = 0; i < 6; i++)
478 {
479 if (strcasecmp(strtrim(argv[i]), words[i]))
480 break;
481 }
482 if (i != 6)
483 {
484 reply(rc, BAD_SIX_WORDS, "GETW", "d", NULL);
485 return;
486 }
487
488 free(rc->id);
489 rc->id = NULL;
490 if (!rc->username)
491 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
492 else
493 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
494}
495
ee47c73a 496void SPIN(reg_client *rc, int argc, char **argv)
497{
498 EXEC SQL BEGIN DECLARE SECTION;
499 char pin[USERS_PIN_SIZE];
500 EXEC SQL END DECLARE SECTION;
501
502 if (!rc->id || argc != 1)
503 {
504 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
505 return;
506 }
507
508 EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id;
509 strtrim(pin);
510 if (strcmp(argv[0], pin) != 0)
511 {
512 reply(rc, BAD_PIN, "GETI", "d", NULL);
513 return;
514 }
515
516 free(rc->id);
517 rc->id = NULL;
518 if (!rc->username)
519 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
520 else
521 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
522}
523
b50f996d 524void LOGN(reg_client *rc, int argc, char **argv)
525{
526 int i;
527 char *login;
528 long status;
529
530 if (!rc->uid || rc->id || rc->username || argc != 1)
531 {
532 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
533 return;
534 }
535
536 login = argv[0];
537
538 /* make sure someone's not trying to overrun reply */
539 if (strlen(login) > 100)
540 {
541 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
542 rc->lastmod = 0;
543 return;
544 }
545
546 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
547 (login[0] == '_') || isdigit(login[0]))
548 {
549 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
550 3, USERS_LOGIN_SIZE - 1);
551 return;
552 }
553
554 for (i = 0; i < strlen(login); i++)
555 {
556 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
557 {
558 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
559 3, USERS_LOGIN_SIZE - 1);
560 return;
561 }
562 }
563
564 status = check_kerberos(login);
565 if (status == MR_SUCCESS)
566 status = register_user(rc->uid, login);
567
568 if (status == MR_IN_USE)
569 {
570 if (rc->reserved_username)
571 {
572 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
573 rc->username);
574 return;
575 }
576 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
577 return;
578 }
579 else if (status == MR_DOWN)
580 {
581 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
582 return;
583 }
584 else if (status != MR_SUCCESS)
585 {
586 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
587 return;
588 }
589
590 rc->username = strdup(login);
591 if (!rc->username)
592 {
593 com_err(whoami, errno, "in LOGN");
594 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
595 return;
596 }
597 reply(rc, USERNAME_OK, "GETP", "c", NULL, login);
598}
599
600int ctypes[256] = {
601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ - ^O */
602 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^P - ^_ */
603 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* SPACE - / */
604 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, /* 0 - ? */
605 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* : - O */
606 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, /* P - _ */
607 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* ` - o */
608 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, /* p - ^? */
609 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
610 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
612 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
615 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
616 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
617};
618
619void PSWD(reg_client *rc, int argc, char **argv)
620{
621 long status;
622 char *password = argv[0], *p;
623 EXEC SQL BEGIN DECLARE SECTION;
624 char *login = rc->username;
625 EXEC SQL END DECLARE SECTION;
626
627 if (!rc->username || rc->id || argc != 1)
628 {
629 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
630 return;
631 }
632
633 /* password quality checking */
634 if (strlen(password) < 4)
635 {
636 reply(rc, PASSWORD_SHORT, "GETP", "c", NULL);
637 return;
638 }
639
640 if (strlen(password) < 7)
641 {
642 for (p = password + 1; *p; p++)
643 {
644 if (ctypes[*p] != ctypes[*(p - 1)])
645 break;
646 }
647 if (!*p)
648 {
649 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
650 return;
651 }
652 }
653
654 if (!strcasecmp(password, "GykoR-66") ||
655 !strcasecmp(password, "slaRooBey") ||
656 !strcasecmp(password, "krang-its") ||
657 !strcasecmp(password, "2HotPeetzas") ||
658 !strcasecmp(password, "ItzAGurl"))
659 {
660 reply(rc, PASSWORD_SAMPLE, "GETP", "c", NULL);
661 return;
662 }
663
664 status = register_kerberos(rc->username, password);
9c0c1480 665 if (status == MR_QUALITY)
666 {
667 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
668 return;
669 }
670 else if (status == MR_IN_USE)
b50f996d 671 {
672 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
673 rc->username);
674 return;
675 }
676 else if (status)
677 {
678 com_err(whoami, status, "registering username with Kerberos");
679 reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
680 return;
681 }
682 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
683 EXEC SQL COMMIT;
684
685 reply(rc, DONE, "INIT", "c", NULL, rc->username);
686}
687
688void QUIT(reg_client *rc, int argc, char **argv)
689{
690}
691
692/* Register a user in Moira */
693int register_user(int uid, char *username)
694{
695 char uidbuf[10], *qargv[3], *motd = NULL;
696 long status;
697
698 status = mr_connect(hostname);
699 if (status)
700 return status;
701
702 status = mr_motd(&motd);
703 if (status || motd)
704 {
705 mr_disconnect();
706 return MR_DOWN;
707 }
708
709 status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
710 krb_realmofhost(hostname), MOIRA_SNAME,
711 shorthostname, 1, KEYFILE);
712 if (status)
713 status += ERROR_TABLE_BASE_krb;
714 else
715 status = mr_auth("reg_svr");
716 if (status)
717 {
718 com_err(whoami, status, "authenticating to moira");
719 mr_disconnect();
720 return MR_INTERNAL;
721 }
722
723 sprintf(uidbuf, "%d", uid);
724 qargv[0] = uidbuf;
725 qargv[1] = username;
4787f97b 726 qargv[2] = "IMAP";
b50f996d 727 status = mr_query("register_user", 3, qargv, NULL, NULL);
728 mr_disconnect();
729 return status;
730}
731
732
733/* Find some typical available usernames */
734
735char *uname_patterns[] = {
736 "FL", /* johndoe */
737 "fmllllll", /* jmdoe... (last name truncated) */
738 "flllllll", /* jdoe.... ("") */
739 "llllllll", /* doe..... ("") */
740 "fml", /* jmd */
741 "Fl", /* johnd */
742 "Lf", /* doej */
743 "Lfm", /* doejm */
744 "F", /* john */
745};
746int num_patterns = sizeof(uname_patterns) / sizeof(char *);
747
748char *find_usernames(char *first, char *middle, char *last)
749{
750 EXEC SQL BEGIN DECLARE SECTION;
751 char username[2 * USERS_LOGIN_SIZE];
752 int count;
753 EXEC SQL END DECLARE SECTION;
754 int pat, len;
755 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
756
757 fixname(first);
758 fixname(middle);
759 fixname(last);
760
761 for (pat = 0; pat < num_patterns; pat++)
762 {
763 up = username;
764 fp = first;
765 mp = middle;
766 lp = last;
767 for (pp = uname_patterns[pat]; *pp; pp++)
768 {
769 switch (*pp)
770 {
771 case 'f':
772 if (*fp)
773 *up++ = *fp++;
774 break;
775
776 case 'F':
777 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
778 up += sprintf(up, "%s", first);
779 else
780 goto nextpattern;
781 break;
782
783 case 'm':
784 if (!*middle)
785 goto nextpattern;
786 if (*mp)
787 *up++ = *mp++;
788 break;
789
790 case 'l':
791 if (*lp)
792 *up++ = *lp++;
793 break;
794
795 case 'L':
796 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
797 up += sprintf(up, "%s", last);
798 else
799 goto nextpattern;
800 break;
801 }
802 }
803 *up = '\0';
804
d1d04a6c 805 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 806 continue;
807
808 EXEC SQL SELECT COUNT(login) INTO :count FROM users
809 WHERE login = :username;
810 if (sqlca.sqlcode)
8dc13a24 811 {
812 errno = MR_DBMS_ERR;
813 return NULL;
814 }
b50f996d 815 if (count == 0)
816 {
817 EXEC SQL SELECT COUNT(name) INTO :count FROM list
818 WHERE name = :username;
819 if (sqlca.sqlcode)
8dc13a24 820 {
821 errno = MR_DBMS_ERR;
822 return NULL;
823 }
b50f996d 824 }
825 if (count == 0)
826 {
827 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
828 WHERE label = :username;
829 if (sqlca.sqlcode)
8dc13a24 830 {
831 errno = MR_DBMS_ERR;
832 return NULL;
833 }
b50f996d 834 }
835
836 if (count == 0)
837 {
838 if (unames)
839 {
840 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
841 if (!unames)
842 return NULL;
843 strcat(unames, ", ");
844 strcat(unames, username);
845 }
846 else
847 {
848 unames = strdup(username);
849 if (!unames)
850 return NULL;
851 }
852 }
853
854 nextpattern:
855 ;
856 }
857
8dc13a24 858 /* unames will be NULL if we couldn't suggest a username. Clear
859 errno so the caller can distinguish this from an error case. */
860 errno = 0;
b50f996d 861 return unames;
862}
863
864void fixname(char *name)
865{
866 char *s, *d;
867
868 for (s = d = name; *s; s++)
869 {
870 if (isalnum(*s))
871 *d++ = tolower(*s);
872 }
873 *d = '\0';
874}
875
876void *xmalloc(size_t bytes)
877{
878 void *buf = malloc(bytes);
879
880 if (buf)
881 return buf;
882
883 com_err(whoami, errno, "in xmalloc");
884 exit(1);
885}
886
887void *xrealloc(void *ptr, size_t bytes)
888{
889 void *buf = realloc(ptr, bytes);
890
891 if (buf)
892 return buf;
893
894 com_err(whoami, errno, "in xrealloc");
895 exit(1);
896}
897
898char *xstrdup(char *str)
899{
900 char *buf = strdup(str);
901
902 if (buf)
903 return buf;
904
905 com_err(whoami, errno, "in xstrdup");
906 exit(1);
907}
908
909void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
910{
911 if (whoami)
912 {
913 fputs(whoami, stderr);
914 if (cl)
915 fprintf(stderr, "[#%d]", cl->clientid);
916 fputs(": ", stderr);
917 }
918 if (code) {
919 fputs(error_message(code), stderr);
920 fputs(" ", stderr);
921 }
922 if (fmt)
923 vfprintf(stderr, fmt, pvar);
924 putc('\n', stderr);
925}
926
927void sigshut(int sig)
928{
929 state = RS_EXITING;
930}
This page took 0.235553 seconds and 5 git commands to generate.