lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[amitay/samba.git] / source3 / smbd / message.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB messaging
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20    This file handles the messaging system calls for winpopup style
21    messages
22 */
23
24
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "smbprofile.h"
30
31 extern userdom_struct current_user_info;
32
33 struct msg_state {
34         char *from;
35         char *to;
36         char *msg;
37 };
38
39 /****************************************************************************
40  Deliver the message.
41 ****************************************************************************/
42
43 static void msg_deliver(struct msg_state *state)
44 {
45         TALLOC_CTX *frame = talloc_stackframe();
46         char *name = NULL;
47         int i;
48         int fd;
49         char *msg;
50         size_t len;
51         ssize_t sz;
52         fstring alpha_buf;
53         char *s;
54         mode_t mask;
55
56         if (! (*lp_message_command(frame))) {
57                 DEBUG(1,("no messaging command specified\n"));
58                 goto done;
59         }
60
61         /* put it in a temporary file */
62         name = talloc_asprintf(talloc_tos(), "%s/msg.XXXXXX", tmpdir());
63         if (!name) {
64                 goto done;
65         }
66         mask = umask(S_IRWXO | S_IRWXG);
67         fd = mkstemp(name);
68         umask(mask);
69
70         if (fd == -1) {
71                 DEBUG(1, ("can't open message file %s: %s\n", name,
72                           strerror(errno)));
73                 goto done;
74         }
75
76         /*
77          * Incoming message is in DOS codepage format. Convert to UNIX.
78          */
79
80         if (!convert_string_talloc(talloc_tos(), CH_DOS, CH_UNIX, state->msg,
81                                    talloc_get_size(state->msg), (void *)&msg,
82                                    &len)) {
83                 DEBUG(3, ("Conversion failed, delivering message in DOS "
84                           "codepage format\n"));
85                 msg = state->msg;
86         }
87
88         for (i = 0; i < len; i++) {
89                 if ((msg[i] == '\r') &&
90                     (i < (len-1)) && (msg[i+1] == '\n')) {
91                         continue;
92                 }
93                 sz = write(fd, &msg[i], 1);
94                 if ( sz != 1 ) {
95                         DEBUG(0, ("Write error to fd %d: %ld(%s)\n", fd,
96                                   (long)sz, strerror(errno)));
97                 }
98         }
99
100         close(fd);
101
102         /* run the command */
103         s = lp_message_command(frame);
104         if (s == NULL) {
105                 goto done;
106         }
107
108         alpha_strcpy(alpha_buf, state->from, NULL, sizeof(alpha_buf));
109
110         s = talloc_string_sub(talloc_tos(), s, "%f", alpha_buf);
111         if (s == NULL) {
112                 goto done;
113         }
114
115         alpha_strcpy(alpha_buf, state->to, NULL, sizeof(alpha_buf));
116
117         s = talloc_string_sub(talloc_tos(), s, "%t", alpha_buf);
118         if (s == NULL) {
119                 goto done;
120         }
121
122         s = talloc_sub_basic(talloc_tos(), current_user_info.smb_name,
123                              current_user_info.domain, s);
124         if (s == NULL) {
125                 goto done;
126         }
127
128         s = talloc_string_sub(talloc_tos(), s, "%s", name);
129         if (s == NULL) {
130                 goto done;
131         }
132         smbrun(s, NULL, NULL);
133
134  done:
135         TALLOC_FREE(frame);
136         return;
137 }
138
139 /****************************************************************************
140  Reply to a sends.
141  conn POINTER CAN BE NULL HERE !
142 ****************************************************************************/
143
144 void reply_sends(struct smb_request *req)
145 {
146         struct msg_state *state;
147         int len;
148         const uint8_t *msg;
149         const uint8_t *p;
150
151         START_PROFILE(SMBsends);
152
153         if (!(*lp_message_command(talloc_tos()))) {
154                 reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
155                 END_PROFILE(SMBsends);
156                 return;
157         }
158
159         state = talloc(talloc_tos(), struct msg_state);
160
161         p = req->buf + 1;
162         p += srvstr_pull_req_talloc(
163                 state, req, &state->from, p, STR_ASCII|STR_TERMINATE) + 1;
164         p += srvstr_pull_req_talloc(
165                 state, req, &state->to, p, STR_ASCII|STR_TERMINATE) + 1;
166
167         msg = p;
168
169         len = SVAL(msg,0);
170         len = MIN(len, smbreq_bufrem(req, msg+2));
171
172         state->msg = talloc_array(state, char, len);
173
174         if (state->msg == NULL) {
175                 reply_nterror(req, NT_STATUS_NO_MEMORY);
176                 END_PROFILE(SMBsends);
177                 return;
178         }
179
180         memcpy(state->msg, msg+2, len);
181
182         msg_deliver(state);
183
184         reply_outbuf(req, 0, 0);
185
186         END_PROFILE(SMBsends);
187         return;
188 }
189
190 /****************************************************************************
191  Reply to a sendstrt.
192  conn POINTER CAN BE NULL HERE !
193 ****************************************************************************/
194
195 void reply_sendstrt(struct smb_request *req)
196 {
197         struct smbXsrv_connection *xconn = req->xconn;
198         const uint8_t *p;
199
200         START_PROFILE(SMBsendstrt);
201
202         if (!(*lp_message_command(talloc_tos()))) {
203                 reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
204                 END_PROFILE(SMBsendstrt);
205                 return;
206         }
207
208         TALLOC_FREE(xconn->smb1.msg_state);
209
210         xconn->smb1.msg_state = talloc_zero(xconn, struct msg_state);
211
212         if (xconn->smb1.msg_state == NULL) {
213                 reply_nterror(req, NT_STATUS_NO_MEMORY);
214                 END_PROFILE(SMBsendstrt);
215                 return;
216         }
217
218         p = req->buf+1;
219         p += srvstr_pull_req_talloc(
220                 xconn->smb1.msg_state, req,
221                 &xconn->smb1.msg_state->from, p,
222                 STR_ASCII|STR_TERMINATE) + 1;
223         p += srvstr_pull_req_talloc(
224                 xconn->smb1.msg_state, req,
225                 &xconn->smb1.msg_state->to, p,
226                 STR_ASCII|STR_TERMINATE) + 1;
227
228         DEBUG(3, ("SMBsendstrt (from %s to %s)\n",
229                   xconn->smb1.msg_state->from,
230                   xconn->smb1.msg_state->to));
231
232         reply_outbuf(req, 0, 0);
233
234         END_PROFILE(SMBsendstrt);
235         return;
236 }
237
238 /****************************************************************************
239  Reply to a sendtxt.
240  conn POINTER CAN BE NULL HERE !
241 ****************************************************************************/
242
243 void reply_sendtxt(struct smb_request *req)
244 {
245         struct smbXsrv_connection *xconn = req->xconn;
246         int len;
247         const char *msg;
248         char *tmp;
249         size_t old_len;
250
251         START_PROFILE(SMBsendtxt);
252
253         if (! (*lp_message_command(talloc_tos()))) {
254                 reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
255                 END_PROFILE(SMBsendtxt);
256                 return;
257         }
258
259         if ((xconn->smb1.msg_state == NULL) || (req->buflen < 3)) {
260                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
261                 END_PROFILE(SMBsendtxt);
262                 return;
263         }
264
265         msg = (const char *)req->buf + 1;
266
267         old_len = talloc_get_size(xconn->smb1.msg_state->msg);
268
269         len = MIN(SVAL(msg, 0), smbreq_bufrem(req, msg+2));
270
271         tmp = talloc_realloc(xconn->smb1.msg_state,
272                              xconn->smb1.msg_state->msg,
273                              char, old_len + len);
274
275         if (tmp == NULL) {
276                 reply_nterror(req, NT_STATUS_NO_MEMORY);
277                 END_PROFILE(SMBsendtxt);
278                 return;
279         }
280
281         xconn->smb1.msg_state->msg = tmp;
282
283         memcpy(&xconn->smb1.msg_state->msg[old_len], msg+2, len);
284
285         DEBUG( 3, ( "SMBsendtxt\n" ) );
286
287         reply_outbuf(req, 0, 0);
288
289         END_PROFILE(SMBsendtxt);
290         return;
291 }
292
293 /****************************************************************************
294  Reply to a sendend.
295  conn POINTER CAN BE NULL HERE !
296 ****************************************************************************/
297
298 void reply_sendend(struct smb_request *req)
299 {
300         struct smbXsrv_connection *xconn = req->xconn;
301         START_PROFILE(SMBsendend);
302
303         if (! (*lp_message_command(talloc_tos()))) {
304                 reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
305                 END_PROFILE(SMBsendend);
306                 return;
307         }
308
309         DEBUG(3,("SMBsendend\n"));
310
311         msg_deliver(xconn->smb1.msg_state);
312
313         TALLOC_FREE(xconn->smb1.msg_state);
314
315         reply_outbuf(req, 0, 0);
316
317         END_PROFILE(SMBsendend);
318         return;
319 }