]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
Provide support for Kerberos-only accounts.
[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];
9d5ca0f4 304 int uid, status, secure, sqlstatus;
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:
9d5ca0f4 368 case US_REGISTERED_KERBEROS_ONLY:
b50f996d 369 reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
370 return;
371
372 case US_DELETED:
373 reply(rc, ACCOUNT_DELETED, "INIT", "c", NULL, login);
374 return;
375
376 case US_NOT_ALLOWED:
377 reply(rc, NOT_ELIGIBLE, "INIT", "c", NULL);
378 return;
379
380 default:
381 break;
382 }
383
9d5ca0f4 384 rc->user_status = status;
b50f996d 385 rc->uid = uid;
386 sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
387 if (!strcmp(class, "MITS"))
388 strcpy(class, "STAFF");
389 if (secure == 1)
390 {
391 rc->id = strdup(id);
392 if (!rc->id)
393 {
394 com_err(whoami, errno, "in RIFO");
395 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
396 return;
397 }
398 }
399 if (*login != '#')
400 {
401 rc->reserved_username = 1;
402 rc->username = strdup(login);
403 if (!rc->username)
404 {
405 com_err(whoami, errno, "in RIFO");
406 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
407 return;
408 }
409 }
410 else
411 {
412 rc->suggestions = find_usernames(first, middle, last);
8dc13a24 413 if (!rc->suggestions && errno)
b50f996d 414 {
415 com_err(whoami, errno, "in RIFO");
8dc13a24 416 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
b50f996d 417 return;
418 }
419 }
420
421 if (rc->id)
ee47c73a 422 {
423 if (*pin != '\0')
424 reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
425 else
426 reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
427 }
b50f996d 428 else if (!rc->username)
429 reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
430 else
78b14dbc 431 {
9d5ca0f4 432 if (rc->user_status == US_NO_LOGIN_YET ||
433 rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
78b14dbc 434 {
435 status = check_kerberos(login);
9d5ca0f4 436 if (status == MR_SUCCESS &&
437 rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
438 status = register_user(rc->uid, login);
78b14dbc 439 if (status == MR_IN_USE)
440 {
441 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
442 rc->username);
443 return;
444 }
445 else if (status == MR_DOWN)
446 {
447 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
448 return;
449 }
450 else if (status != MR_SUCCESS)
451 {
452 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
453 error_message(status));
454 return;
455 }
456 }
457 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
458 }
b50f996d 459}
460
461void SWRD(reg_client *rc, int argc, char **argv)
462{
463 char *words[6];
464 int i;
465
466 if (!rc->id || argc != 6)
467 {
468 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
469 return;
470 }
471
472 getwordlist(rc->id, words);
473 for (i = 0; i < 6; i++)
474 {
475 if (strcasecmp(strtrim(argv[i]), words[i]))
476 break;
477 }
478 if (i != 6)
479 {
480 reply(rc, BAD_SIX_WORDS, "GETW", "d", NULL);
481 return;
482 }
483
484 free(rc->id);
485 rc->id = NULL;
486 if (!rc->username)
487 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
488 else
489 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
490}
491
ee47c73a 492void SPIN(reg_client *rc, int argc, char **argv)
493{
494 EXEC SQL BEGIN DECLARE SECTION;
495 char pin[USERS_PIN_SIZE];
496 EXEC SQL END DECLARE SECTION;
497
498 if (!rc->id || argc != 1)
499 {
500 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
501 return;
502 }
503
504 EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id;
505 strtrim(pin);
506 if (strcmp(argv[0], pin) != 0)
507 {
508 reply(rc, BAD_PIN, "GETI", "d", NULL);
509 return;
510 }
511
512 free(rc->id);
513 rc->id = NULL;
514 if (!rc->username)
515 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
516 else
517 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
518}
519
b50f996d 520void LOGN(reg_client *rc, int argc, char **argv)
521{
522 int i;
523 char *login;
524 long status;
525
526 if (!rc->uid || rc->id || rc->username || argc != 1)
527 {
528 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
529 return;
530 }
531
532 login = argv[0];
533
534 /* make sure someone's not trying to overrun reply */
535 if (strlen(login) > 100)
536 {
537 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
538 rc->lastmod = 0;
539 return;
540 }
541
542 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
543 (login[0] == '_') || isdigit(login[0]))
544 {
545 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
546 3, USERS_LOGIN_SIZE - 1);
547 return;
548 }
549
550 for (i = 0; i < strlen(login); i++)
551 {
552 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
553 {
554 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
555 3, USERS_LOGIN_SIZE - 1);
556 return;
557 }
558 }
559
560 status = check_kerberos(login);
561 if (status == MR_SUCCESS)
9d5ca0f4 562 {
563 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
564 EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
565 else
566 status = register_user(rc->uid, login);
567 }
b50f996d 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 }
9d5ca0f4 682
683 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
684 EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
685 else
686 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
b50f996d 687 EXEC SQL COMMIT;
688
689 reply(rc, DONE, "INIT", "c", NULL, rc->username);
690}
691
692void QUIT(reg_client *rc, int argc, char **argv)
693{
694}
695
696/* Register a user in Moira */
697int register_user(int uid, char *username)
698{
699 char uidbuf[10], *qargv[3], *motd = NULL;
700 long status;
701
702 status = mr_connect(hostname);
703 if (status)
704 return status;
705
706 status = mr_motd(&motd);
707 if (status || motd)
708 {
709 mr_disconnect();
710 return MR_DOWN;
711 }
712
713 status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
714 krb_realmofhost(hostname), MOIRA_SNAME,
715 shorthostname, 1, KEYFILE);
716 if (status)
717 status += ERROR_TABLE_BASE_krb;
718 else
719 status = mr_auth("reg_svr");
720 if (status)
721 {
722 com_err(whoami, status, "authenticating to moira");
723 mr_disconnect();
724 return MR_INTERNAL;
725 }
726
727 sprintf(uidbuf, "%d", uid);
728 qargv[0] = uidbuf;
729 qargv[1] = username;
4787f97b 730 qargv[2] = "IMAP";
b50f996d 731 status = mr_query("register_user", 3, qargv, NULL, NULL);
732 mr_disconnect();
733 return status;
734}
735
736
737/* Find some typical available usernames */
738
739char *uname_patterns[] = {
740 "FL", /* johndoe */
741 "fmllllll", /* jmdoe... (last name truncated) */
742 "flllllll", /* jdoe.... ("") */
743 "llllllll", /* doe..... ("") */
744 "fml", /* jmd */
745 "Fl", /* johnd */
746 "Lf", /* doej */
747 "Lfm", /* doejm */
748 "F", /* john */
749};
750int num_patterns = sizeof(uname_patterns) / sizeof(char *);
751
752char *find_usernames(char *first, char *middle, char *last)
753{
754 EXEC SQL BEGIN DECLARE SECTION;
755 char username[2 * USERS_LOGIN_SIZE];
756 int count;
757 EXEC SQL END DECLARE SECTION;
758 int pat, len;
759 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
760
761 fixname(first);
762 fixname(middle);
763 fixname(last);
764
765 for (pat = 0; pat < num_patterns; pat++)
766 {
767 up = username;
768 fp = first;
769 mp = middle;
770 lp = last;
771 for (pp = uname_patterns[pat]; *pp; pp++)
772 {
773 switch (*pp)
774 {
775 case 'f':
776 if (*fp)
777 *up++ = *fp++;
778 break;
779
780 case 'F':
781 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
782 up += sprintf(up, "%s", first);
783 else
784 goto nextpattern;
785 break;
786
787 case 'm':
788 if (!*middle)
789 goto nextpattern;
790 if (*mp)
791 *up++ = *mp++;
792 break;
793
794 case 'l':
795 if (*lp)
796 *up++ = *lp++;
797 break;
798
799 case 'L':
800 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
801 up += sprintf(up, "%s", last);
802 else
803 goto nextpattern;
804 break;
805 }
806 }
807 *up = '\0';
808
d1d04a6c 809 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 810 continue;
811
812 EXEC SQL SELECT COUNT(login) INTO :count FROM users
813 WHERE login = :username;
814 if (sqlca.sqlcode)
8dc13a24 815 {
816 errno = MR_DBMS_ERR;
817 return NULL;
818 }
b50f996d 819 if (count == 0)
820 {
821 EXEC SQL SELECT COUNT(name) INTO :count FROM list
822 WHERE name = :username;
823 if (sqlca.sqlcode)
8dc13a24 824 {
825 errno = MR_DBMS_ERR;
826 return NULL;
827 }
b50f996d 828 }
829 if (count == 0)
830 {
831 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
832 WHERE label = :username;
833 if (sqlca.sqlcode)
8dc13a24 834 {
835 errno = MR_DBMS_ERR;
836 return NULL;
837 }
b50f996d 838 }
839
840 if (count == 0)
841 {
842 if (unames)
843 {
844 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
845 if (!unames)
846 return NULL;
847 strcat(unames, ", ");
848 strcat(unames, username);
849 }
850 else
851 {
852 unames = strdup(username);
853 if (!unames)
854 return NULL;
855 }
856 }
857
858 nextpattern:
859 ;
860 }
861
8dc13a24 862 /* unames will be NULL if we couldn't suggest a username. Clear
863 errno so the caller can distinguish this from an error case. */
864 errno = 0;
b50f996d 865 return unames;
866}
867
868void fixname(char *name)
869{
870 char *s, *d;
871
872 for (s = d = name; *s; s++)
873 {
874 if (isalnum(*s))
875 *d++ = tolower(*s);
876 }
877 *d = '\0';
878}
879
880void *xmalloc(size_t bytes)
881{
882 void *buf = malloc(bytes);
883
884 if (buf)
885 return buf;
886
887 com_err(whoami, errno, "in xmalloc");
888 exit(1);
889}
890
891void *xrealloc(void *ptr, size_t bytes)
892{
893 void *buf = realloc(ptr, bytes);
894
895 if (buf)
896 return buf;
897
898 com_err(whoami, errno, "in xrealloc");
899 exit(1);
900}
901
902char *xstrdup(char *str)
903{
904 char *buf = strdup(str);
905
906 if (buf)
907 return buf;
908
909 com_err(whoami, errno, "in xstrdup");
910 exit(1);
911}
912
913void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
914{
915 if (whoami)
916 {
917 fputs(whoami, stderr);
918 if (cl)
919 fprintf(stderr, "[#%d]", cl->clientid);
920 fputs(": ", stderr);
921 }
922 if (code) {
923 fputs(error_message(code), stderr);
924 fputs(" ", stderr);
925 }
926 if (fmt)
927 vfprintf(stderr, fmt, pvar);
928 putc('\n', stderr);
929}
930
931void sigshut(int sig)
932{
933 state = RS_EXITING;
934}
This page took 0.187424 seconds and 5 git commands to generate.