1 /*
2   a composite API for quering file system information
3 */
4 
5 #include "includes.h"
6 #include "libcli/raw/libcliraw.h"
7 #include "libcli/composite/composite.h"
8 #include "libcli/smb_composite/smb_composite.h"
9 
10 /* the stages of this call */
11 enum fsinfo_stage {FSINFO_CONNECT, FSINFO_QUERY};
12 
13 
14 static void fsinfo_raw_handler(struct smbcli_request *req);
15 static void fsinfo_composite_handler(struct composite_context *c);
16 static void fsinfo_state_handler(struct composite_context *c);
17 
18 struct fsinfo_state {
19 	enum fsinfo_stage stage;
20 	struct composite_context *creq;
21 	struct smb_composite_fsinfo *io;
22 	struct smb_composite_connect *connect;
23 	union smb_fsinfo *fsinfo;
24 	struct smbcli_tree *tree;
25 	struct smbcli_request *req;
26 };
27 
fsinfo_connect(struct composite_context * c,struct smb_composite_fsinfo * io)28 static NTSTATUS fsinfo_connect(struct composite_context *c,
29 			       struct smb_composite_fsinfo *io)
30 {
31 	NTSTATUS status;
32 	struct fsinfo_state *state;
33 	state = talloc_get_type(c->private_data, struct fsinfo_state);
34 
35 	status = smb_composite_connect_recv(state->creq, c);
36 	NT_STATUS_NOT_OK_RETURN(status);
37 
38 	state->fsinfo = talloc(state, union smb_fsinfo);
39 	NT_STATUS_HAVE_NO_MEMORY(state->fsinfo);
40 
41 	state->fsinfo->generic.level = io->in.level;
42 
43 	state->req = smb_raw_fsinfo_send(state->connect->out.tree,
44 					 state,
45 					 state->fsinfo);
46 	NT_STATUS_HAVE_NO_MEMORY(state->req);
47 
48 	state->req->async.private = c;
49 	state->req->async.fn = fsinfo_raw_handler;
50 
51 	state->stage = FSINFO_QUERY;
52 	c->event_ctx = talloc_reference(c, state->req->session->transport->socket->event.ctx);
53 
54 	return NT_STATUS_OK;
55 }
56 
fsinfo_query(struct composite_context * c,struct smb_composite_fsinfo * io)57 static NTSTATUS fsinfo_query(struct composite_context *c,
58 			       struct smb_composite_fsinfo *io)
59 {
60 	NTSTATUS status;
61 	struct fsinfo_state *state;
62 	state = talloc_get_type(c->private_data, struct fsinfo_state);
63 
64 	status = smb_raw_fsinfo_recv(state->req, state, state->fsinfo);
65 	NT_STATUS_NOT_OK_RETURN(status);
66 
67 	state->io->out.fsinfo = state->fsinfo;
68 
69 	c->state = COMPOSITE_STATE_DONE;
70 
71 	if (c->async.fn)
72 		c->async.fn(c);
73 
74 	return NT_STATUS_OK;
75 
76 }
77 
78 /*
79   handler for completion of a sub-request in fsinfo
80 */
fsinfo_state_handler(struct composite_context * creq)81 static void fsinfo_state_handler(struct composite_context *creq)
82 {
83 	struct fsinfo_state *state = talloc_get_type(creq->private_data, struct fsinfo_state);
84 
85 	/* when this handler is called, the stage indicates what
86 	   call has just finished */
87 	switch (state->stage) {
88 	case FSINFO_CONNECT:
89 		creq->status = fsinfo_connect(creq, state->io);
90 		break;
91 
92 	case FSINFO_QUERY:
93 		creq->status = fsinfo_query(creq, state->io);
94 		break;
95 	}
96 
97 	if (!NT_STATUS_IS_OK(creq->status)) {
98 		creq->state = COMPOSITE_STATE_ERROR;
99 	}
100 
101 	if (creq->state >= COMPOSITE_STATE_DONE && creq->async.fn) {
102 		creq->async.fn(creq);
103 	}
104 }
105 
106 /*
107    As raw and composite handlers take different requests, we need to handlers
108    to adapt both for the same state machine in fsinfo_state_handler()
109 */
fsinfo_raw_handler(struct smbcli_request * req)110 static void fsinfo_raw_handler(struct smbcli_request *req)
111 {
112 	struct composite_context *c = talloc_get_type(req->async.private,
113 						      struct composite_context);
114 	fsinfo_state_handler(c);
115 }
116 
fsinfo_composite_handler(struct composite_context * creq)117 static void fsinfo_composite_handler(struct composite_context *creq)
118 {
119 	struct composite_context *c = talloc_get_type(creq->async.private_data,
120 						      struct composite_context);
121 	fsinfo_state_handler(c);
122 }
123 
124 /*
125   composite fsinfo call - connects to a tree and queries a file system information
126 */
smb_composite_fsinfo_send(struct smbcli_tree * tree,struct smb_composite_fsinfo * io)127 struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree,
128 						    struct smb_composite_fsinfo *io)
129 {
130 	struct composite_context *c;
131 	struct fsinfo_state *state;
132 
133 	c = talloc_zero(tree, struct composite_context);
134 	if (c == NULL) goto failed;
135 
136 	state = talloc(c, struct fsinfo_state);
137 	if (state == NULL) goto failed;
138 
139 	state->io = io;
140 
141 	state->connect = talloc(state, struct smb_composite_connect);
142 
143 	if (state->connect == NULL) goto failed;
144 
145 	state->connect->in.dest_host    = io->in.dest_host;
146 	state->connect->in.port         = io->in.port;
147 	state->connect->in.called_name  = io->in.called_name;
148 	state->connect->in.service      = io->in.service;
149 	state->connect->in.service_type = io->in.service_type;
150 	state->connect->in.credentials  = io->in.credentials;
151 	state->connect->in.fallback_to_anonymous = False;
152 	state->connect->in.workgroup    = io->in.workgroup;
153 
154 	c->state = COMPOSITE_STATE_IN_PROGRESS;
155 	state->stage = FSINFO_CONNECT;
156 	c->event_ctx = talloc_reference(c,  tree->session->transport->socket->event.ctx);
157 	c->private_data = state;
158 
159 	state->creq = smb_composite_connect_send(state->connect, state,
160 						 c->event_ctx);
161 
162 	if (state->creq == NULL) goto failed;
163 
164 	state->creq->async.private_data = c;
165 	state->creq->async.fn = fsinfo_composite_handler;
166 
167 	return c;
168 failed:
169 	talloc_free(c);
170 	return NULL;
171 }
172 
173 /*
174   composite fsinfo call - recv side
175 */
smb_composite_fsinfo_recv(struct composite_context * c,TALLOC_CTX * mem_ctx)176 NTSTATUS smb_composite_fsinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
177 {
178 	NTSTATUS status;
179 
180 	status = composite_wait(c);
181 
182 	if (NT_STATUS_IS_OK(status)) {
183 		struct fsinfo_state *state = talloc_get_type(c->private_data, struct fsinfo_state);
184 		talloc_steal(mem_ctx, state->io->out.fsinfo);
185 	}
186 
187 	talloc_free(c);
188 	return status;
189 }
190 
191 
192 /*
193   composite fsinfo call - sync interface
194 */
smb_composite_fsinfo(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_composite_fsinfo * io)195 NTSTATUS smb_composite_fsinfo(struct smbcli_tree *tree,
196 			      TALLOC_CTX *mem_ctx,
197 			      struct smb_composite_fsinfo *io)
198 {
199 	struct composite_context *c = smb_composite_fsinfo_send(tree, io);
200 	return smb_composite_fsinfo_recv(c, mem_ctx);
201 }
202 
203