]> andersk Git - moira.git/blob - reg_svr/reg_svr.c
pd
[moira.git] / reg_svr / reg_svr.c
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      Server for user registration with SMS and Kerberos.
9  *
10  *      This program is a client of the SMS server and the Kerberos
11  *      admin_server, and is a server for the userreg program.
12  * 
13  *      $Log$
14  *      Revision 1.9  1988-07-26 14:50:40  qjb
15  *      Added comments and did some cleaning up in preparation for rewrite.
16  *      This version will not run; the last version that will is 1.8.
17  *
18  * Revision 1.8  88/07/20  15:39:25  mar
19  * find realm at runtime; don't use hard-coded one
20  * 
21  * Revision 1.7  88/02/08  15:08:15  mar
22  * Moved header file locations
23  * 
24  * Revision 1.6  87/09/21  15:19:11  wesommer
25  * Allow numbers, _, and . as legal characters in the username.
26  * 
27  * Revision 1.5  87/09/10  22:18:32  wesommer
28  * Clean up output format.
29  * 
30  * Revision 1.4  87/09/04  23:33:19  wesommer
31  * Deleted test scaffolding (second oops.)
32  * 
33  * Revision 1.3  87/09/03  03:05:18  wesommer
34  * Version used for userreg tests.
35  * 
36  * Revision 1.2  87/08/22  18:39:45  wesommer
37  * User registration server.
38  * 
39  * Revision 1.1  87/07/31  15:48:13  wesommer
40  * Initial revision
41  * 
42  */
43
44 #ifndef lint
45 static char *rcsid_reg_svr_c = "$Header$";
46 #endif lint
47
48 #include <stdio.h>
49 #include <sys/types.h>
50 #include <sys/file.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <netdb.h>
54 #include <krb.h>
55 #include <des.h>
56 #include <errno.h>
57 #include <ctype.h>
58 #include "ureg_err.h"
59 #include "ureg_proto.h"
60 #include "sms.h"
61 #include "admin_server.h"
62 #include "admin_err.h"
63 #include <strings.h>
64
65 #define WHOAMI "reg_svr"        /* Name of program for SMS logging */
66 #define CUR_SMS_VERSION SMS_VERSION_2     /* SMS version for this program */
67
68
69 extern int abort();
70 extern char *strdup();
71 extern char *malloc();
72 extern int krb_err_base;
73 extern char admin_errmsg[];
74
75 extern int errno;               /* Unix error number */
76
77 /* This is the structure used to store the packet information */
78 /* Get this.  The register client gets the MIT id of the registering user
79    in plain text, encrypts it with one-way password encryption,
80    concatenates that to the plain text id, and then des encrypts the
81    whole thing using the password encrypted id as the key!  The result
82    goes in enc_mitid. */
83 struct msg 
84 {    
85     u_long version;             /* SMS version */
86     u_long request;             /* Request */
87     char *first;                /* First name */
88     char *last;                 /* Last name */
89     char *enc_mitid;            /* See comment above */
90     int enc_mitid_len;          /* Length of enc_mitid */
91 };
92
93 static char errmsg[BUFSIZ];
94
95 main()
96 {
97     struct servent *sp;         /* Service info from /etc/services */
98     int s;                      /* Socket descriptor */
99     struct sockaddr_in sin;     /* Internet style socket address */
100     int addrlen;                /* Size of socket address (sin) */
101     char packet[BUFSIZ];        /* Buffer for packet transmission */
102     int pktlen;                 /* Size of packet */
103     u_long seqno;               /* Sequence number for packet transmission */
104     struct msg message;         /* Storage for parsed packet */
105     int status;                 /* General purpose error status */
106     
107     /* Error messages sent one line at a time */
108     setlinebuf(stderr);
109     
110     /* Initialize user registration error table */
111     init_ureg_err_tbl();
112     
113     /* Get service information from /etc/services */
114     if ((sp = getservbyname("sms_ureg", "udp")) == NULL) 
115     {
116         fprintf(stderr, "Unknown service sms_ureg/udp\n");
117         exit(1);
118     }
119     
120     /* Get an internet style datagram socket */
121     if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) 
122     {
123         perror("socket");
124         exit(1);
125     }
126     bzero((char *)&sin, sizeof(sin));
127     
128     sin.sin_family = AF_INET;
129     sin.sin_port = sp->s_port;
130     sin.sin_addr.s_addr = INADDR_ANY;
131     
132     /* Bind a name to the socket */
133     if (bind(s, &sin, sizeof(sin)) < 0) 
134     {
135         perror("bind");
136         exit(1);
137     }
138     
139     /* Connect to the SMS server */
140     if ((status = sms_connect()) != SMS_SUCCESS) 
141     {
142         com_err(WHOAMI, status, " on connect");
143         exit(1);
144     }
145     
146     /* Authorize, telling the server who you are */
147     if ((status = sms_auth(WHOAMI)) != SMS_SUCCESS) 
148     {
149         com_err(WHOAMI, status, " on auth");
150         exit(1);
151     }
152     
153     /* Sit around waiting for requests from the client. */
154     for (;;) 
155     {
156         com_err(WHOAMI, 0, "Ready for next request");
157         addrlen = sizeof(sin);
158         bzero(errmsg, BUFSIZ);
159         /* Receive a packet into buf. */
160         if ((pktlen = recvfrom(s,packet,sizeof(packet),0,&sin,&addrlen)) < 0) 
161         {
162             perror("recvfrom");
163             if (errno == EINTR) continue;
164             exit(1);
165         }
166         
167         /* Parse a request packet */
168         if ((status = parse_pkt(packet, pktlen, &seqno, &message)) != 0) 
169         {
170             pktlen = sizeof(packet);
171             /* Format packet to send back to the client */
172             format_pkt(packet, &pktlen, seqno, status, (char *)NULL);
173             /* Report the error the the client */
174             (void) sendto(s, packet, pktlen, 0, &sin, addrlen);
175             continue;
176         }
177         
178         /* do action */
179         switch((int)message.request) 
180         {
181           case UREG_VERIFY_USER:
182             status = verify_user(&message);
183             break;
184           case UREG_RESERVE_LOGIN:
185             status = reserve_user(&message);
186             break;
187           case UREG_SET_PASSWORD:
188             status = set_password(&message);
189             break;
190             
191           default:
192             status = UREG_UNKNOWN_REQUEST;
193             break;
194         }
195         
196         /* Report what happened to client */
197         pktlen = sizeof(packet);
198         format_pkt(packet, &pktlen, seqno, status, errmsg);
199         sendto(s, packet, pktlen, 0, &sin, addrlen);
200     }
201 }
202
203 int got_one;
204 int reg_status;
205 char *mit_id;
206 char *reg_misc;
207 int reg_misc_len;
208 int user_id;
209
210 #define min(a,b) ((a)>(b)?(b):(a))
211
212 int validate_idno(message, db_mit_id, first, last)
213   struct msg *message;          /* Formatted packet */
214   char *db_mit_id;              /* Encrypted MIT ID from SMS database */
215   char *first, *last;           /* First and last name for MIT ID encryption */
216 /* This routine makes sure that the ID from the database matches
217    the ID sent accross in the packet.  The information in the packet
218    was created in the following way:
219
220    The plain text ID number was encrypted via crypt() resulting in
221    the form that would appear in the SMS database.  This is 
222    concatinated to the plain text ID so that the ID string contains
223    plain text ID followed by a null followed by the encrypted ID.
224    The whole thing is then DES encrypted using the encrypted ID as 
225    the source of the key.
226
227    This routine tries each encrypted ID in the database that belongs
228    to someone with this user's first and last name and tries to 
229    decrypt the packet with this information. */
230 {
231     C_Block key;                /* The key for DES en/decryption */
232     Key_schedule sched;         /* En/decryption schedule */
233     static char decrypt[BUFSIZ];   /* Buffer to hold decrypted information */
234     long decrypt_len;           /* Length of decypted ID information */
235     char recrypt[14];           /* Buffer to hold re-encrypted information */
236     static char hashid[14];     /* Buffer to hold one-way encrypted ID */
237     char idnumber[BUFSIZ];      /* Buffer to hold plain-text ID */
238     char *temp;                 /* A temporary storage buffer */
239     int len;                    /*  */
240     
241     mit_id = 0;
242     /* Make the decrypted information length the same as the encrypted
243        information length.  Both are integral multples of eight bytes 
244        because of the DES encryption routines. */
245     decrypt_len = (long)message->enc_mitid_len;
246     
247     /* Get key from the one-way encrypted ID in the SMS database */
248     string_to_key(db_mit_id, key);
249     /* Get schedule from key */
250     key_sched(key, sched);
251     /* Decrypt information from packet using this key.  Since decrypt_len
252        is an integral multiple of eight bytes, it will probably be null-
253        padded. */
254     pcbc_encrypt(message->enc_mitid, decrypt, \
255                  decrypt_len, sched, key, DECRYPT);
256     
257     /* Extract the plain text and encrypted ID fields from the decrypted
258        packet information. */
259     /* Since the decrypted information starts with the plain-text ID
260        followed by a null, if the decryption worked, this will only 
261        copy the plain text part of the decrypted information.  It is
262        important that strncpy be used because if we are not using the
263        correct key, there is no guarantee that a null will occur
264        anywhere in the string. */
265     (void) strncpy(idnumber, decrypt, decrypt_len);
266     /* Point temp to the end of the plain text ID number. */
267     temp = decrypt + strlen(idnumber) + 1;
268     /* Find out how much more room there is. */
269     len = message->enc_mitid_len - (temp - decrypt);
270     /* Copy the next 14 bytes of the decrypted information into 
271        hashid if there are 14 more bytes to copy.  There will be
272        if we have the right key. */
273     (void) strncpy(hashid, temp, min(len, 14));
274     /* Point temp to the end of the encrypted ID field */
275     temp += strlen(hashid) + 1;
276     /* Find out how much more room there is. */
277     len = message->enc_mitid_len - (temp - decrypt);
278     
279     /* Now compare encrypted ID's returning with an error if they
280        don't match. */
281     if (strcmp(hashid, db_mit_id)) return 1;
282     encrypt_mitid(recrypt, idnumber, first, last);
283     /* Now compare encrypted plain text to ID from database. */
284     if (strcmp(recrypt, db_mit_id)) return 1;
285     
286     /* We made it. */
287     reg_misc = temp;
288     reg_misc_len = len;
289     mit_id = hashid;
290     return 0;
291 }
292
293 static int status_in_db;
294
295 vfy_callbk(argc, argv, p_message)
296   int argc;                     /* Should sanity check this.. */
297   char **argv;
298   char *p_message;
299 {
300     struct msg *message = (struct msg *)p_message;
301     char *db_mit_id;
302     char *firstname, *lastname;
303     int status;
304     
305     if (got_one) return 0;
306     reg_status = 0;
307     
308     db_mit_id = argv[8];
309     firstname = argv[5];
310     lastname = argv[4];
311     
312     status = validate_idno(message, db_mit_id, firstname, lastname);
313     if (status) return 0; /* Nope; decryption failed */
314     
315     status_in_db = atoi(argv[7]);
316     reg_status = status_in_db;    
317     
318     if (status_in_db != 0) 
319     {
320         (void) strcpy(errmsg, argv[0]);
321     }
322     user_id = atoi(argv[1]);
323     got_one = 1;
324     return 0;
325 }    
326
327 encrypt_mitid(buf, idnumber, first, last)
328     char *buf, *idnumber, *first, *last;
329 {
330     char salt[3];
331     extern char *crypt();
332     
333 #define _tolower(c) ((c)|0x60)
334     
335     salt[0] = _tolower(last[0]);
336     salt[1] = _tolower(first[0]);
337     salt[2] = 0;
338     
339     (void) strcpy(buf, crypt(&idnumber[2], salt));
340 }
341
342 int verify_user(message)
343   struct msg *message;
344 {
345     char *argv[3];
346     int status;
347     
348     com_err(WHOAMI, 0, " verify_user %s %s\n",
349             message->first, message->last);
350     argv[0] = "get_user_by_first_and_last";
351     argv[1] = message->first;
352     argv[2] = message->last;
353     got_one = 0;
354     
355     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
356     
357     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
358     if (!got_one && !status)
359         status = UREG_USER_NOT_FOUND;
360     
361     if (status != SMS_SUCCESS) goto punt;
362     
363     if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
364     if (reg_status == 2) status = UREG_NO_PASSWD_YET;
365     
366   punt:
367     return status;
368 }
369
370 reserve_user(message)
371   struct msg *message;
372 {
373     char *argv[3];
374     int status;
375     int i;
376     char *login;
377     char uid_buf[20];
378     char realm[REALM_SZ];
379     
380     com_err(WHOAMI, 0, " reserve_user %s %s\n",
381             message->first, message->last);
382     
383     argv[0] = "gufl";           /* get_user_by_first_and_last */
384     argv[1] = message->first;
385     argv[2] = message->last;
386     got_one = 0;
387     
388     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
389     
390     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
391     if (!got_one && !status)
392         status = UREG_USER_NOT_FOUND;
393     
394     if (status != SMS_SUCCESS) goto punt;
395     if (reg_status != 0) 
396     {
397         status = UREG_ALREADY_REGISTERED;
398         goto punt;
399     }
400     /*
401      * He's made it past this phase already.
402      */
403     if (status_in_db == 2) 
404     {
405         status = 0;
406         goto punt;
407     }
408     
409     for (i = 0; i < reg_misc_len && reg_misc[i]; i++) 
410     {
411         if (!islower(reg_misc[i]) && !isdigit(reg_misc[i]) &&
412             reg_misc[i] != '_' && reg_misc[i] != '.') 
413         {
414             status = UREG_INVALID_UNAME;
415             goto punt;
416         }
417     }
418     if (i < 3 || i > 8) 
419     {
420         status = UREG_INVALID_UNAME;
421         goto punt;
422     }
423     login = reg_misc;
424     
425     /* Send request to kerberos admin_server for login name */
426     /* get keys */
427     if ((status = get_krbrlm(realm, 1)) != KSUCCESS) 
428     {
429         status += krb_err_base;
430         goto punt;
431     }
432     status = get_svc_in_tkt("register", "sms", realm,
433                             "changepw", "kerberos",
434                             1, "/etc/srvtab");
435     if (status) 
436     {
437         status += krb_err_base;
438         goto punt;
439     }
440     
441     /* send set password request to kerberos admin_server */
442     (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
443     /* for backwards-compat. */
444     
445     status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "", 
446                         "", uid_buf);
447     
448     if (status) 
449     {
450         if (status == ADMIN_SERVER_ERROR) 
451         {
452             printf("Server error: %s\n", admin_errmsg);
453             
454             if (strcmp(admin_errmsg,
455                        "Principal already in kerberos database.") ==0)
456                 status = UREG_LOGIN_USED;
457         }
458         goto punt;
459     }
460     
461     dest_tkt();
462     /* If valid: */
463     
464     /* Set login name */
465     status = set_login(login, mit_id);
466     
467     
468     if (status) 
469     {
470         com_err("set_login", status, (char *)0);
471         goto punt;
472     }
473     /* choose post office */
474     
475     status = choose_pobox(login);
476     if (status) 
477     {
478         com_err("choose_pobox", status, (char *)0);
479         goto punt;
480     }
481     /* create group */
482     
483     status = create_group(login);
484     if (status == SMS_LIST) status = UREG_LOGIN_USED;
485     
486     if (status) 
487     {
488         com_err("create_group", status, (char *)0);
489         goto punt;
490     }
491     /* set quota entry, create filsys */
492     
493     status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
494     if (status == SMS_FILESYS_EXISTS) status = UREG_LOGIN_USED;
495     if (status) 
496     {
497         com_err("alloc_filsys", status, (char *)0);
498         goto punt;
499     }
500     /* set filsys and status in SMS database */
501     
502     status = set_status_filsys(reg_misc, mit_id);
503     if (status) 
504     {
505         com_err("set_filsys", status, (char *)0);
506         goto punt;
507     }
508   punt:
509     dest_tkt();
510     
511     com_err(WHOAMI, status, " returned from reserve_user");
512     return status;
513 }
514
515 set_password(message)
516   struct msg *message;
517 {
518     char *argv[3];
519     int status;
520     char uid_buf[10];
521     char realm[REALM_SZ];
522     
523     com_err(WHOAMI, 0, " set_password %s %s\n",
524             message->first, message->last);
525     
526     /* validate that user is who he claims to be */
527     
528     argv[0] = "get_user_by_first_and_last";
529     argv[1] = message->first;
530     argv[2] = message->last;
531     got_one = 0;
532     
533     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
534     
535     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
536     if (!got_one && !status)
537         status = UREG_USER_NOT_FOUND;
538     
539     if (status != SMS_SUCCESS) goto punt;
540     
541     /* validate that state is equal to '2' (login, but no password) */
542     
543     if (reg_status != 2) 
544     {
545         status = UREG_NO_LOGIN_YET;
546         goto punt;
547     }
548     
549     /* get keys */
550     if ((status = get_krbrlm(realm, 1)) != KSUCCESS) 
551     {
552         goto punt;
553     }
554     status = get_svc_in_tkt("register", "sms", realm,
555                             "changepw", "kerberos",
556                             1, "/etc/srvtab");
557     if (status) 
558     {
559         status += krb_err_base;
560         goto punt;
561     }
562     
563     (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
564     /* for backwards-compat. */
565     /* send set password request to kerberos admin_server */
566     /**####**/
567     status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, errmsg, "", 
568                         reg_misc, uid_buf);
569     
570     if (status) goto punt;
571     dest_tkt();
572     /**#####**/    
573     status = set_final_status(errmsg, mit_id);
574     
575     /* reflect reply to client */
576   punt:
577     dest_tkt();
578     return status;
579 }
580
581 parse_pkt(packet, pktlen, seqnop, messagep)
582   char *packet;
583   int pktlen;
584   u_long *seqnop;
585   struct msg *messagep;
586   /* This routine checks a packet and puts the information in it in
587        a structure if it is valid. */
588 {
589     if (pktlen < 4) return UREG_BROKEN_PACKET;
590     /* Extract the SMS version from the packet */
591     bcopy(packet, (char *)&messagep->version, sizeof(long));
592     /* Convert byte order from network to host */
593     messagep->version = ntohl(messagep->version);
594     /* Verify version */
595     if (messagep->version != CUR_SMS_VERSION) return UREG_WRONG_VERSION;
596     
597     packet += 4;
598     pktlen -= 4;
599     
600     if (pktlen < 4) return UREG_BROKEN_PACKET;
601     /* Extract the sequence number from the packet */
602     bcopy(packet, (char *)seqnop, sizeof(long));
603     
604     packet += 4;
605     pktlen -= 4;
606     
607     if (pktlen < 4) return UREG_BROKEN_PACKET;
608     /* Extract the request from the packet */
609     bcopy(packet, (char *)(&messagep->request), sizeof(long));
610     messagep->request = ntohl(messagep->request);
611     packet += 4;
612     pktlen -= 4;
613     
614     /* Extract first name from the packet */
615     messagep->first = packet;
616     
617     /* Scan forward until null appears in the packet or there
618        is no more packet! */
619     for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
620     if (pktlen <= 0) return UREG_BROKEN_PACKET;
621     
622     /* Skip over the null */
623     packet++, pktlen--;
624     
625     /* Extract last name from the packet */
626     messagep->last = packet;
627     
628     for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
629     if (pktlen <= 0) return UREG_BROKEN_PACKET;
630     
631     packet++, pktlen--;
632     
633     if (pktlen <= 0) return UREG_BROKEN_PACKET;
634     
635     /* Extract MIT id information from packet; see comment on
636        struct msg. */
637     messagep->enc_mitid = packet;
638     messagep->enc_mitid_len = pktlen;
639     
640     return 0;
641 }
642
643 format_pkt(packet, pktlenp, seqno, status, message)
644   char *packet;
645   int *pktlenp;
646   u_long seqno;
647   int status;
648   char *message;
649   /* This routine prepares a packet to send back to the client. */
650 {
651     u_long vers = htonl((u_long)CUR_SMS_VERSION);
652     status = htonl((u_long)status);
653     
654     /* Put current SMS version into the packet */
655     bcopy((char *)&vers, packet, sizeof(long));
656     /* Put sequence number into the packet */
657     bcopy((char *)&seqno, packet+sizeof(long), sizeof(long));
658     /* Put error status into the packet */
659     bcopy((char *)&status, packet+ 2*sizeof(long), sizeof(long));
660     *pktlenp = sizeof(long) * 3;
661     /* Copy the message into the packet */
662     (void) strcpy(packet+3*sizeof(long), message);
663     (*pktlenp) += strlen(message);
664 }
665
666 store_user(argc, argv, argp)
667   int argc;
668   char **argv;
669     char *argp;
670 {
671     char **retv = (char **) argp;
672     int i;
673     
674     for (i = 0; i < argc; i++) 
675     {
676         if (retv[i]) 
677         {
678             free(retv[i]);
679             retv[i]=0;
680         }
681         retv[i] = strdup(argv[i]);
682     }
683     return 0;
684 }
685
686
687 /*
688  * Set login name of user with "idnumber" to be "username"
689  */
690
691 set_login(username, idnumber)
692   char *username;
693   char *idnumber;
694 {
695     char *argv[2];
696     int status, i;
697     char *retv[13];
698     
699     argv[0] = "get_user_by_mitid";
700     argv[1] = idnumber;
701     
702     for (i=0; i<13; i++) 
703     {
704         retv[i] = 0;
705     }
706     
707     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
708     if (status) return status;
709     
710     retv[0] = retv[1];
711     retv[1] = username;
712     if (retv[4]) free(retv[4]);
713     retv[4] = "null";           /* No such filesystem */
714     
715     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
716     
717     status = sms_query("update_user", 12, retv, abort, 0);
718     retv[1] = 0;
719     retv[4] = 0;
720     
721     for (i=1; i<12; i++) 
722     {
723         if (retv[i]) free(retv[i]);
724         retv[i] = 0;
725     }
726     
727     return status;
728 }    
729
730 /*
731  * Set the status and filsys of user with username "uname" and filesys filsys.
732  */
733
734 set_status_filsys(username, idnumber)
735   char *username;
736   char *idnumber;
737 {
738     char *argv[2];
739     int status, i;
740     char *retv[13];
741     
742     argv[0] = "get_user_by_mitid";
743     argv[1] = idnumber;
744     
745     for (i=0; i<13; i++) 
746     {
747         retv[i] = 0;
748     }
749     
750     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
751     if (status) return status;
752     
753     retv[0] = retv[1];
754     
755     free(retv[4]);
756     retv[4] = username;
757     
758     free(retv[8]);
759     retv[8] = "2";
760     
761     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
762     
763     status = sms_query("update_user", 12, retv, abort, 0);
764     retv[4] = 0;
765     retv[8] = 0;
766     for (i=1; i<12; i++) 
767     {
768         if (retv[i]) free(retv[i]);
769         retv[i] = 0;
770     }
771     return status;
772 }    
773 /*
774  * Set the status and filsys of user with username "uname" and filesys filsys.
775  */
776
777 set_final_status(username, idnumber)
778   char *username;
779   char *idnumber;
780 {
781     char *argv[2];
782     int status, i;
783     char *retv[13];
784     
785     argv[0] = "get_user_by_mitid";
786     argv[1] = idnumber;
787     
788     for (i=0; i<13; i++) 
789     {
790         retv[i] = 0;
791     }
792     
793     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
794     if (status) return status;
795     
796     retv[0] = retv[1];
797     
798     free(retv[8]);
799     retv[8] = "1";
800     
801     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
802     
803     status = sms_query("update_user", 12, retv, abort, 0);
804     retv[8] = 0;
805     for (i=1; i<12; i++) 
806     {
807         if (retv[i]) free(retv[i]);
808         retv[i] = 0;
809     }
810     return status;
811 }    
812
813 create_group(login)
814   char *login;
815 {
816     int status;
817     static char *cr[] = 
818     {
819         "add_user_group",
820         0,
821     };
822     
823     cr[1] = login;
824     
825     return sms_query_internal(2, cr, abort, 0);
826 }    
827
828 /*
829  * Local Variables:
830  * mode: c
831  * c-argdecl-indent: 2
832  * c-brace-offset: -4
833  * c-continued-statement-offset: 2
834  * c-indent-level: 4
835  * c-label-offset: -2
836  * End:
837  */
This page took 0.106789 seconds and 5 git commands to generate.