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