]> andersk Git - moira.git/blob - reg_svr/reg_svr.pc
If the user only supplies an MIT ID without a name, we don't love them.
[moira.git] / reg_svr / reg_svr.pc
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
38 EXEC SQL INCLUDE sqlca;
39
40 RCSID("$Header$");
41
42 char *whoami, *hostname, *shorthostname;
43
44 char *find_usernames(char *first, char *middle, char *last);
45 void fixname(char *name);
46 int register_user(int uid, char *username);
47 void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar);
48 void sigshut(int);
49
50 reg_client *cl = NULL;
51 enum { RS_RUNNING, RS_SLEEPING, RS_EXITING } state = RS_RUNNING;
52
53 int 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         {
163           state = RS_SLEEPING;
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         {
168           state = RS_RUNNING;
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
296 void 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];
303   char class[USERS_TYPE_SIZE], pin[USERS_PIN_SIZE];
304   int uid, status, secure, sqlstatus, count;
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   EXEC SQL SELECT count(login) INTO :count FROM users WHERE clearid = :id;
319
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
323     SELECT login, unix_uid, status, secure, pin, first, middle, last, type
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,
329         :secure, :pin, :first, :middle, :last, :class;
330       if (sqlca.sqlcode)
331         break;
332       strtrim(login);
333       strtrim(first);
334       strtrim(middle);
335       strtrim(last);
336       strtrim(class);
337       strtrim(pin);
338
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
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;
361       if (!*ufirst && !*ulast)
362         continue;
363
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:
381     case US_REGISTERED_KERBEROS_ONLY:
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
397   rc->user_status = status;
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);
426       if (!rc->suggestions && errno)
427         {
428           com_err(whoami, errno, "in RIFO");
429           reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
430           return;
431         }
432     }
433
434   if (rc->id)
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     }
441   else if (!rc->username)
442     reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
443   else
444     {
445       if (rc->user_status == US_NO_LOGIN_YET || 
446           rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
447         {
448           status = check_kerberos(login);
449           if (status == MR_SUCCESS && 
450               rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
451             status = register_user(rc->uid, login);
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     }
472 }
473
474 void 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
505 void 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
517   EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id
518     AND status = :rc->user_status;
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
531     {
532       register_user(rc->uid, rc->username);
533       reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
534     }
535 }
536
537 void 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)
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     }
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
617 int 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
636 void 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);
682   if (status == MR_QUALITY)
683     {
684       reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
685       return;
686     }
687   else if (status == MR_IN_USE)
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     }
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;
704   EXEC SQL COMMIT;
705
706   reply(rc, DONE, "INIT", "c", NULL, rc->username);
707 }
708
709 void QUIT(reg_client *rc, int argc, char **argv)
710 {
711 }
712
713 /* Register a user in Moira */
714 int 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;
747   qargv[2] = "IMAP";
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
756 char *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 };
767 int num_patterns = sizeof(uname_patterns) / sizeof(char *);
768
769 char *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
826       if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
827         continue;
828
829       EXEC SQL SELECT COUNT(login) INTO :count FROM users
830         WHERE login = :username;
831       if (sqlca.sqlcode)
832         {
833           errno = MR_DBMS_ERR;
834           return NULL;
835         }
836       if (count == 0)
837         {
838           EXEC SQL SELECT COUNT(name) INTO :count FROM list
839             WHERE name = :username;
840           if (sqlca.sqlcode)
841             {
842               errno = MR_DBMS_ERR;
843               return NULL;
844             }
845         }
846       if (count == 0)
847         {
848           EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
849             WHERE label = :username;
850           if (sqlca.sqlcode)
851             {
852               errno = MR_DBMS_ERR;
853               return NULL;
854             }
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
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;
882   return unames;
883 }
884
885 void 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
897 void *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
908 void *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
919 char *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
930 void 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
948 void sigshut(int sig)
949 {
950   state = RS_EXITING;
951 }
This page took 0.386023 seconds and 5 git commands to generate.