]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/status.c
implemented config.h
[netatalk.git] / etc / afpd / status.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <sys/types.h>
15
16 #ifdef BSD4_4
17 #include <sys/param.h>
18 #ifndef USE_GETHOSTID
19 #include <sys/sysctl.h>
20 #endif
21 #endif
22
23 #include <netatalk/at.h>
24 #include <netatalk/endian.h>
25 #include <atalk/dsi.h>
26 #include <atalk/atp.h>
27 #include <atalk/asp.h>
28 #include <atalk/nbp.h>
29
30 #include "globals.h"  /* includes <netdb.h> */
31 #include "status.h"
32 #include "afp_config.h"
33 #include "icon.h"
34
35 static void status_flags(char *data, const int ipok,
36                          const unsigned char passwdbits)
37 {
38     u_int16_t           status;
39
40     status = AFPSRVRINFO_COPY;
41     if (passwdbits & PASSWD_SET) /* some uams may not allow this. */
42       status |= AFPSRVRINFO_PASSWD;
43     if (passwdbits & PASSWD_NOSAVE)
44       status |= AFPSRVRINFO_NOSAVEPASSWD;
45     status |= AFPSRVRINFO_SRVSIGNATURE;
46     /* only advertise tcp/ip if we have a valid address */
47     if (ipok)
48       status |= AFPSRVRINFO_TCPIP;
49     status |= AFPSRVRINFO_SRVMSGS; 
50     status |= AFPSRVRINFO_SRVNOTIFY;
51     status |= AFPSRVRINFO_FASTBOZO;
52     status = htons(status);
53     memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status));
54 }
55
56 static int status_server(char *data, const char *server)
57 {
58     char                *start = data;
59     char                *Obj, *Type, *Zone;
60     u_int16_t           status;
61     int                 len;
62
63     /* make room for all offsets before server name */
64     data += AFPSTATUS_PRELEN;
65
66     /* extract the obj part of the server */
67     Obj = (char *) server;
68     nbp_name(server, &Obj, &Type, &Zone);
69     len = strlen(Obj);
70     *data++ = len;
71     memcpy( data, Obj, len );
72     if ((len + 1) & 1) /* pad server name and length byte to even boundary */
73       len++;
74     data += len;
75
76     /* make room for signature and net address offset. save location of 
77      * signature offset. 
78      *
79      * NOTE: technically, we don't need to reserve space for the
80      * signature and net address offsets if they're not going to be
81      * used. as there are no offsets after them, it doesn't hurt to
82      * have them specified though. so, we just do that to simplify
83      * things.  
84      */
85     len = data - start;
86     status = htons(len + AFPSTATUS_POSTLEN);
87     memcpy(start + AFPSTATUS_MACHOFF, &status, sizeof(status));
88     return len; /* return the offset to beginning of signature offset */
89 }
90
91 static void status_machine(char *data)
92 {
93     char                *start = data;
94     u_int16_t           status;
95     int                 len;
96 #ifdef AFS
97     const char          *machine = "afs";
98 #else !AFS
99     const char          *machine = "unix";
100 #endif
101
102     memcpy(&status, start + AFPSTATUS_MACHOFF, sizeof(status));
103     data += ntohs( status );
104     len = strlen( machine );
105     *data++ = len;
106     memcpy( data, machine, len );
107     data += len;
108     status = htons(data - start);
109     memcpy(start + AFPSTATUS_VERSOFF, &status, sizeof(status));
110 }
111
112
113 /* server signature is a 16-byte quantity */
114 static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi, 
115                                   const char *hostname)
116 {
117   char                 *status;
118   int                  i;
119   u_int16_t            offset, sigoff;
120   long                 hostid;
121   static int           id = 0;
122 #ifdef BSD4_4
123   int                  mib[2];
124   size_t               len;
125 #endif
126
127   status = data;
128
129   /* get server signature offset */
130   memcpy(&offset, data + *servoffset, sizeof(offset));
131   sigoff = offset = ntohs(offset);
132
133   /* jump to server signature offset */
134   data += offset;
135
136   /* 16-byte signature consists of copies of the hostid */
137 #if defined(BSD4_4) && defined(USE_GETHOSTID)
138   mib[0] = CTL_KERN;
139   mib[1] = KERN_HOSTID;
140   len = sizeof(hostid);
141   sysctl(mib, 2, &hostid, &len, NULL, 0);
142 #else
143   hostid = gethostid();
144 #endif
145   if (!hostid) {
146     if (dsi)
147       hostid = dsi->server.sin_addr.s_addr;
148     else {
149       struct hostent *host;
150       
151       if ((host = gethostbyname(hostname)))
152         hostid = ((struct in_addr *) host->h_addr)->s_addr;
153     }
154   }
155
156   /* it turns out that a server signature screws up separate 
157    * servers running on the same machine. to work around that, 
158    * i add in an increment */
159   hostid += id;
160   id++;
161   for (i = 0; i < 16; i += sizeof(hostid)) {
162     memcpy(data, &hostid, sizeof(hostid));
163     data += sizeof(hostid);
164   }
165
166   /* calculate net address offset */
167   *servoffset += sizeof(offset);
168   offset = htons(data - status);
169   memcpy(status + *servoffset, &offset, sizeof(offset));
170   return sigoff;
171 }
172
173 static int status_netaddress(char *data, const int servoffset, 
174                              const ASP asp, const DSI *dsi, 
175                              const char *fqdn)
176 {
177     char               *begin;
178     u_int16_t          offset;
179     
180     begin = data;
181
182     /* get net address offset */
183     memcpy(&offset, data + servoffset, sizeof(offset));
184     data += ntohs(offset);
185
186     /* format: 
187        Address count (byte) 
188        len (byte = sizeof(length + address type + address) 
189        address type (byte, ip address = 0x01, ip + port = 0x02,
190                            ddp address = 0x03, fqdn = 0x04) 
191        address (up to 254 bytes, ip = 4, ip + port = 6, ddp = 4)
192        */
193
194     /* number of addresses. this currently screws up if we have a dsi
195        connection, but we don't have the ip address. to get around this,
196        we turn off the status flag for tcp/ip. */
197     *data++ = (fqdn ? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0);
198
199     /* handle DNS names */
200     if (fqdn) {
201       int len = strlen(fqdn) + 2;
202       *data++ = len;
203       *data++ = 0x04;
204       memcpy(data, fqdn, len);
205       data += len;
206     }
207
208     /* ip address */
209     if (dsi) {
210       const struct sockaddr_in *inaddr = &dsi->server;
211
212       if (inaddr->sin_port == htons(DSI_AFPOVERTCP_PORT)) {
213         *data++ = 6; /* length */
214         *data++ = 0x01; /* basic ip address */
215         memcpy(data, &inaddr->sin_addr.s_addr,
216                sizeof(inaddr->sin_addr.s_addr));
217         data += sizeof(inaddr->sin_addr.s_addr);
218       } else {
219         /* ip address + port */
220         *data++ = 8; 
221         *data++ = 0x02; /* ip address with port */ 
222         memcpy(data, &inaddr->sin_addr.s_addr,
223                sizeof(inaddr->sin_addr.s_addr));
224         data += sizeof(inaddr->sin_addr.s_addr);
225         memcpy(data, &inaddr->sin_port, sizeof(inaddr->sin_port));
226         data += sizeof(inaddr->sin_port);
227       }
228     }
229
230 #ifndef NO_DDP
231     if (asp) {
232       const struct sockaddr_at *ddpaddr = atp_sockaddr(asp->asp_atp);
233       
234       /* ddp address */
235       *data++ = 6;
236       *data++ = 0x03; /* ddp address */
237       memcpy(data, &ddpaddr->sat_addr.s_net, sizeof(ddpaddr->sat_addr.s_net));
238       data += sizeof(ddpaddr->sat_addr.s_net);
239       memcpy(data, &ddpaddr->sat_addr.s_node, 
240              sizeof(ddpaddr->sat_addr.s_node));
241       data += sizeof(ddpaddr->sat_addr.s_node);
242       memcpy(data, &ddpaddr->sat_port, sizeof(ddpaddr->sat_port));
243       data += sizeof(ddpaddr->sat_port);
244     }
245 #endif
246
247     /* return length of buffer */
248     return (data - begin);
249 }
250
251 /* returns actual offset to signature */
252 static void status_icon(char *data, const char *icondata, 
253                         const int iconlen, const int sigoffset)
254 {
255     char                *start = data;
256     char                *sigdata = data + sigoffset;
257     u_int16_t           ret, status;
258
259     memcpy(&status, start + AFPSTATUS_ICONOFF, sizeof(status));
260     if ( icondata == NULL ) {
261         ret = status;
262         memset(start + AFPSTATUS_ICONOFF, 0, sizeof(status));
263     } else {
264         data += ntohs( status );
265         memcpy( data, icondata, iconlen);
266         data += iconlen;
267         ret = htons(data - start);
268     }
269     
270     /* put in signature offset */
271     if (sigoffset)
272       memcpy(sigdata, &ret, sizeof(ret));
273 }
274
275 const void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig,
276                         const struct afp_options *options)
277 {
278   ASP asp;
279   DSI *dsi;
280   char *status;
281   int c, sigoff;
282
283   if (!(aspconfig || dsiconfig) || !options)
284     return;
285
286   if (aspconfig) {
287     asp = aspconfig->obj.handle;
288     status = aspconfig->status;
289   } else 
290     asp = NULL;
291
292   if (dsiconfig) {
293     dsi = dsiconfig->obj.handle;
294     if (!aspconfig)
295       status = dsiconfig->status;
296   } else 
297     dsi = NULL;
298
299   /*
300    * These routines must be called in order -- earlier calls
301    * set the offsets for later calls.
302    *
303    * using structs is a bad idea, but that's what the original code
304    * does. solaris, in fact, will segfault with them. so, now
305    * we just use the powers of #defines and memcpy.
306    *
307    * reply block layout (offsets are 16-bit quantities):
308    * machine type offset -> AFP version count offset ->
309    * UAM count offset -> vol icon/mask offset -> flags ->
310    *
311    * server name [padded to even boundary] -> signature offset ->
312    * network address offset ->
313    *
314    * at the appropriate offsets:
315    * machine type, afp versions, uams, server signature
316    * (16-bytes), network addresses, volume icon/mask 
317    */
318
319   status_flags(status, options->fqdn || 
320                (dsiconfig && dsi->server.sin_addr.s_addr),
321                options->passwdbits);
322   /* returns offset to signature offset */
323   c = status_server(status, options->server ? options->server :
324                              options->hostname); 
325   status_machine(status);
326   status_versions(status);
327   status_uams(status, options->uamlist);
328   if (options->flags & OPTION_CUSTOMICON) 
329     status_icon(status, icon, sizeof(icon), c); 
330   else 
331     status_icon(status, apple_atalk_icon, sizeof(apple_atalk_icon), c);
332
333   sigoff = status_signature(status, &c, dsi, options->hostname); 
334   
335   /* returns length */
336   c = status_netaddress(status, c, asp, dsi, options->fqdn); 
337
338
339 #ifndef NO_DDP
340   if (aspconfig) {
341     asp_setstatus(asp, status, c);
342     aspconfig->signature = status + sigoff;
343     aspconfig->statuslen = c;
344   }
345 #endif
346
347   if (dsiconfig) {
348     if (aspconfig) { /* copy to dsiconfig */
349       memcpy(dsiconfig->status, status, ATP_MAXDATA);
350       status = dsiconfig->status;
351     }
352       
353     if ((options->flags & OPTION_CUSTOMICON) == 0) {
354       status_icon(status, apple_tcp_icon, sizeof(apple_tcp_icon), 0);
355     } 
356     dsi_setstatus(dsi, status, c);
357     dsiconfig->signature = status + sigoff;
358     dsiconfig->statuslen = c;
359   }
360 }
361
362 /* this is the same as asp/dsi_getstatus */
363 int afp_getsrvrinfo(obj, ibuf, ibuflen, rbuf, rbuflen )
364     AFPObj      *obj;
365     char        *ibuf, *rbuf;
366     int         ibuflen, *rbuflen;
367 {
368     AFPConfig *config = obj->config;
369
370     memcpy(rbuf, config->status, config->statuslen);
371     *rbuflen = config->statuslen;
372     return AFP_OK;
373 }