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