source: trunk/athena/bin/lert/lertsrv.c @ 11791

Revision 11791, 6.9 KB checked in by ghudson, 26 years ago (diff)
From amu: use strerror().
Line 
1/*
2
3   file: lertsrv.c
4   provides the core of the lert msg service
5   take a message, check the authentication, grab a user record, and return.
6
7   based on cmisrv.c: checkmyid server process
8
9 */
10
11#include <stdio.h>
12#include <krb.h>
13#include <des.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <sys/socket.h>
18#include <sys/uio.h>
19#include <ndbm.h>
20#include <netinet/in.h>
21#include <netdb.h>
22#include <sys/time.h>
23#include <hesiod.h>
24#include <string.h>
25#include <pwd.h>
26#include <sys/utsname.h>
27#include <errno.h>
28#include "lert.h"
29
30main(argc, argv)
31int argc;
32char *argv[];
33{
34  int s;                        /* The Socket */
35  register int i;               /* Iterator variable */
36  struct sockaddr_in sin;
37  struct sockaddr *burp_me;
38  struct sockaddr_in from;
39  char packet[2048];
40  int plen;
41  char opacket[2048];
42  int oplen;
43  int fromlen;
44  int status;
45  int len;
46  AUTH_DAT ad;
47  KTEXT_ST authent;
48  KTEXT_ST ktxt;
49  int atime;
50  char *tb, *cp;
51  FILE *logf;
52  /* for krb_mk_priv */
53  des_key_schedule sched;               /* session key schedule */
54  struct hostent *hp;
55/*
56  char hostname[256];
57 */
58  struct utsname thishost;
59
60#ifdef LOGGING
61    setbuf(stdout, NULL);
62#endif
63 
64  s = socket(AF_INET, SOCK_DGRAM, 0);
65
66  /*
67    clear the socket structure
68    */
69  memset(&sin, 0, sizeof(sin));
70  sin.sin_family = AF_INET;
71  sin.sin_port = htons(LERT_PORT);
72  burp_me = (struct sockaddr *)&sin;
73
74  if(bind(s, burp_me, sizeof(sin)) < 0) {
75    fprintf(stderr, "%s: Unable to bind socket: %s\n",
76            argv[0], strerror(errno));
77    exit (1);
78  }
79
80  fromlen = sizeof(from);
81
82
83  /*
84    for krb_mk_priv
85   */
86
87/*
88  gethostname(hostname, sizeof(hostname));
89 */
90  if (uname(&thishost) == -1) {
91    fprintf(stderr, "%s: Unable to get system information: %s\n",
92            argv[0], strerror(errno));
93    exit (1);
94  }
95  hp = gethostbyname(thishost.nodename);
96  if (hp == NULL) {
97    fprintf(stderr, "%s: Unable to get host name information: %s\n",
98            argv[0], strerror(errno));
99    exit (1);
100  }
101
102  memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
103 
104
105  for (;;) {
106    plen = recvfrom(s, packet, 2048, 0, (struct sockaddr *) &from, &fromlen);
107    if (plen < 0) {
108      fprintf(stderr, "lertsrv: Error during recv: %s\n",
109              strerror(errno));
110      sleep (1);                /* Prevent infinite cpu hog loop */
111      continue;
112    }
113
114#ifdef DEBUG
115    fprintf(stderr, "lertsrv: Received packet of length %d\n", plen);
116#endif
117
118    if (packet[0] != LERT_VERSION) {
119      fprintf(stderr, "lertsrv: Received packet with bad version: %d\n",
120              packet[0]);
121      continue;
122    }
123   
124    /*
125      Copy authenticator into aligned region
126      */
127    memcpy(&authent, &packet[LERT_LENGTH], sizeof(authent));
128
129    status = krb_rd_req(&authent, LERT_SERVICE, LERT_HOME,
130                        /*
131                          from.sin_addr,
132                          but other code showed 0 for any from address
133                          */
134                        0,
135                        /*
136                          if you get a srvtab, make sure you put it in,
137                          if default, use ""
138                          */
139                        &ad, LERTS_SRVTAB);
140   
141    if (status != KSUCCESS) {
142      fprintf(stderr, "lertsrv: Kerberos failure: %s\n", krb_err_txt[status]);
143      continue;
144    }
145
146    opacket[0] = LERT_VERSION;
147    if ((strlen(ad.pinst) != 0) || (strcmp(ad.prealm, "ATHENA.MIT.EDU"))) {
148      fprintf(stderr, "lertsrv: %s.%s@%s -- Not null instance ATHENA realm.\n",
149              ad.pname, ad.pinst, ad.prealm);
150      opacket[1] = LERT_NOT_IN_DB;
151      opacket[2] = '\0';
152    } else {
153      get_user(ad.pname, &(opacket[1]), ad.checksum);
154    }
155    /*
156      PREPARE KRB_MK_PRIV MESSAGE
157      */
158
159    /*
160      Get key schedule for session key
161      for a while, inadvertently fed empty ad.session in
162      and it seemed to be okay!
163      resulted in client not being able to decode, with
164      41 - data stream modified - error return
165      */
166    des_key_sched(ad.session, sched);
167
168    /*
169      Make the encrypted message
170      length - version, code, data, plus terminating '\0'
171      */
172    len = krb_mk_priv(opacket,
173                      ktxt.dat,
174                      LERT_CHECK + (strlen(&(opacket[LERT_CHECK]))) + 1,
175                      sched,
176                      ad.session,
177                      &sin,
178                      &from);
179
180    /*
181      Send it
182      */
183
184    if(sendto(s,
185              (char *)ktxt.dat,
186              len,
187              0,   /* flags! */
188              (struct sockaddr *) &from,
189              sizeof(from)) < 0) {
190      fprintf(stderr, "lertsrv: sendto failed: %s\n",
191              strerror(errno));
192    }
193    memset(&from, 0, sizeof(from));     /* Avoid confusion, zeroize now */
194  }
195  return (0);
196}
197
198/*
199   options:
200   1.  open, read, and close db each access
201   2.  open db and hold state.  do fstat or other testing to
202       see about changes, close and reopen if needed.
203   3.  open it.  hope to hell administrators don't forget to kill and
204       reboot if they make any changes.  keep lucky rabbit's foot
205       close for rubbing during inevitable problems...
206   4.  probably others, if I spent more time thinking about it.
207
208selected: open, read, close.  no state information needed.  may be
209slow if we start getting lots of use (30,000 logins...that could be a
210lot of use...) but it's safe and easy.
211
212speed up--open and do fstat's, I suppose.  could read the db into
213memory, then make the update program signal us to reread, I guess, but
214let's do simple first.
215
216 */
217
218get_user(pname, result, onetime)
219char * pname;
220char * result;
221int onetime;
222{
223  DBM *dbm_open();
224  DBM *db;
225  DBM *db2;
226  datum data;
227  datum key;
228  datum data2;
229  datum key2;
230  char result2[128];
231
232  /*
233    prepare nil return
234    */
235  result[0] = LERT_FREE;
236  result[1] = '\0';
237
238  /*
239    open the database
240    */
241  db = dbm_open(LERTS_DATA, O_RDWR, 0600);
242  if (db == NULL) {
243    fprintf(stderr, "Unable to open lert's database file %s: %s.\n",
244            LERTS_DATA, strerror(errno));
245    return(LERT_NO_DB);
246  }
247
248  key.dptr = pname;
249  key.dsize = strlen(pname) + 1;
250
251  /*
252    get the user
253    */
254
255  data = dbm_fetch(db, key);
256  if (data.dptr == NULL) {
257    /* not in db */
258    dbm_close(db);
259#ifdef LOGGING
260    fprintf(stdout, "lertsrv: user %s not in db\n", pname);
261#endif
262    return(LERT_NOT_IN_DB);
263  } else {
264    /*
265      gotta
266      */
267    strncpy(&(result[1]), data.dptr, data.dsize);
268    result[data.dsize + 1] = '\0';
269    /*
270      conditional on the user requesting one time
271      as long as they are live in the regular db, leave them there.
272      */
273    if (onetime) {
274      /*
275        log them in db
276        */
277      db2 = dbm_open(LERTS_LOG, O_RDWR|O_CREAT, 0600);
278      if (db2 == NULL) {
279        fprintf(stderr, "Unable to open lert's log database %s: %s.\n",
280                LERTS_LOG, strerror(errno));
281      } else {
282        data2 = dbm_fetch(db2, key);
283        if (data2.dptr == NULL) {
284          /* not in db */
285          dbm_store(db2, key, data, DBM_INSERT);
286        } else {
287          /* in db ... build a string... */
288          strncpy(result2, data2.dptr, data2.dsize);
289          strncpy(&(result2[data2.dsize]), data.dptr, data.dsize);
290          data2.dptr = result2;
291          data2.dsize += data.dsize;
292          dbm_store(db2, key, data2, DBM_REPLACE);
293        }
294        dbm_close(db2);
295      }
296      dbm_delete(db, key);
297    }
298    dbm_close(db);
299  }
300  result[0] = LERT_MSG;
301#ifdef LOGGING
302    fprintf(stdout, "lertsrv: user %s in db with groups :%s:\n", pname, result);
303#endif
304  return(LERT_GOTCHA);
305}
306
307
Note: See TracBrowser for help on using the repository browser.