1/*
2 * $Id: messages.c,v 1.23 2009-11-24 15:44:40 didg Exp $
3 *
4 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved.  See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#ifdef HAVE_UNISTD_H
13#include <unistd.h>
14#endif /* HAVE_UNISTD_H */
15#include <stdio.h>
16#include <string.h>
17#include <errno.h>
18#include <stdlib.h>
19#include <atalk/afp.h>
20#include <atalk/dsi.h>
21#include <atalk/util.h>
22#include <atalk/logger.h>
23#include <atalk/globals.h>
24
25#include "misc.h"
26
27
28#define MAXMESGSIZE 199
29
30/* this is only used by afpd children, so it's okay. */
31static char servermesg[MAXPATHLEN] = "";
32static char localized_message[MAXPATHLEN] = "";
33
34void setmessage(const char *message)
35{
36    strlcpy(servermesg, message, MAXMESGSIZE);
37}
38
39void readmessage(AFPObj *obj)
40{
41    /* Read server message from file defined as SERVERTEXT */
42#ifdef SERVERTEXT
43    FILE *message;
44    char * filename;
45    unsigned int i;
46    int rc;
47    static int c;
48    uid_t euid;
49    u_int32_t maxmsgsize;
50
51    maxmsgsize = (obj->proto == AFPPROTO_DSI)?MIN(MAX(((DSI*)obj->handle)->attn_quantum, MAXMESGSIZE),MAXPATHLEN):MAXMESGSIZE;
52
53    i=0;
54    /* Construct file name SERVERTEXT/message.[pid] */
55    if ( NULL == (filename=(char*) malloc(sizeof(SERVERTEXT)+15)) ) {
56	LOG(log_error, logtype_afpd, "readmessage: malloc: %s", strerror(errno) );
57        return;
58    }
59
60    sprintf(filename, "%s/message.%d", SERVERTEXT, getpid());
61
62#ifdef DEBUG
63    LOG(log_debug9, logtype_afpd, "Reading file %s ", filename);
64#endif
65
66    message=fopen(filename, "r");
67    if (message==NULL) {
68        /* try without the process id */
69        sprintf(filename, "%s/message", SERVERTEXT);
70        message=fopen(filename, "r");
71    }
72
73    /* if either message.pid or message exists */
74    if (message!=NULL) {
75        /* added while loop to get characters and put in servermesg */
76        while ((( c=fgetc(message)) != EOF) && (i < (maxmsgsize - 1))) {
77            if ( c == '\n')  c = ' ';
78            servermesg[i++] = c;
79        }
80        servermesg[i] = 0;
81
82        /* cleanup */
83        fclose(message);
84
85        /* Save effective uid and switch to root to delete file. */
86        /* Delete will probably fail otherwise, but let's try anyways */
87        euid = geteuid();
88        if (seteuid(0) < 0) {
89            LOG(log_error, logtype_afpd, "Could not switch back to root: %s",
90				strerror(errno));
91        }
92
93        if ((rc = unlink(filename)) != 0)
94	    LOG(log_error, logtype_afpd, "File '%s' could not be deleted", strerror(errno));
95
96        /* Drop privs again, failing this is very bad */
97        if (seteuid(euid) < 0) {
98            LOG(log_error, logtype_afpd, "Could not switch back to uid %d: %s", euid, strerror(errno));
99            exit(EXITERR_SYS);
100        }
101
102        if (rc < 0) {
103            LOG(log_error, logtype_afpd, "Error deleting %s: %s", filename, strerror(rc));
104        }
105#ifdef DEBUG
106        else {
107            LOG(log_debug9, logtype_afpd, "Deleted %s", filename);
108        }
109
110        LOG(log_debug9, logtype_afpd, "Set server message to \"%s\"", servermesg);
111#endif
112    }
113    free(filename);
114#endif /* SERVERTEXT */
115}
116
117int afp_getsrvrmesg(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
118{
119    char *message;
120    u_int16_t type, bitmap;
121    u_int16_t msgsize;
122    size_t outlen = 0;
123    size_t msglen = 0;
124    int utf8 = 0;
125
126    *rbuflen = 0;
127
128    msgsize = (obj->proto == AFPPROTO_DSI)?MAX(((DSI*)obj->handle)->attn_quantum, MAXMESGSIZE):MAXMESGSIZE;
129
130    memcpy(&type, ibuf + 2, sizeof(type));
131    memcpy(&bitmap, ibuf + 4, sizeof(bitmap));
132
133    message = servermesg;
134    switch (ntohs(type)) {
135    case AFPMESG_LOGIN: /* login */
136        /* at least TIGER loses server messages
137         * if it receives a server msg attention before
138         * it has asked the login msg...
139         * Workaround: concatenate the two if any, ugly.
140         */
141        if (*message && *obj->options.loginmesg) {
142            strlcat(message, " - ", MAXMESGSIZE);
143        }
144        strlcat(message, obj->options.loginmesg, MAXMESGSIZE);
145        break;
146    case AFPMESG_SERVER: /* server */
147        break;
148    default:
149        return AFPERR_BITMAP;
150    }
151
152    /* output format:
153     * message type:   2 bytes
154     * bitmap:         2 bytes
155     * message length: 1 byte ( 2 bytes for utf8)
156     * message:        up to 199 bytes (dsi attn_quantum for utf8)
157     */
158    memcpy(rbuf, &type, sizeof(type));
159    rbuf += sizeof(type);
160    *rbuflen += sizeof(type);
161    memcpy(rbuf, &bitmap, sizeof(bitmap));
162    rbuf += sizeof(bitmap);
163    *rbuflen += sizeof(bitmap);
164
165    utf8 = ntohs(bitmap) & 2;
166    msglen = strlen(message);
167    if (msglen > msgsize)
168        msglen = msgsize;
169
170    if (msglen) {
171        if ( (size_t)-1 == (outlen = convert_string(obj->options.unixcharset, utf8?CH_UTF8_MAC:obj->options.maccharset,
172                                                    message, msglen, localized_message, msgsize)) )
173        {
174    	    memcpy(rbuf+((utf8)?2:1), message, msglen); /*FIXME*/
175	    outlen = msglen;
176        }
177        else
178        {
179	    memcpy(rbuf+((utf8)?2:1), localized_message, outlen);
180        }
181    }
182
183    if ( utf8 ) {
184	/* UTF8 message, 2 byte length */
185	msgsize = htons(outlen);
186    	memcpy(rbuf, &msgsize, sizeof(msgsize));
187	*rbuflen += sizeof(msgsize);
188    }
189    else {
190        *rbuf = outlen;
191	*rbuflen += 1;
192    }
193    *rbuflen += outlen;
194    *message = 0;
195    return AFP_OK;
196}
197