Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 : Copyright (C) Andrew Bartlett 2011
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 : #include "replace.h"
21 : #include "lib/util/debug.h"
22 : #include "lib/util/fault.h"
23 : #include "lib/util/server_id.h"
24 : #include "lib/util/byteorder.h"
25 : #include "librpc/gen_ndr/server_id.h"
26 :
27 2182 : bool server_id_same_process(const struct server_id *p1,
28 : const struct server_id *p2)
29 : {
30 2182 : return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
31 : }
32 :
33 246262 : int server_id_cmp(const struct server_id *p1, const struct server_id *p2)
34 : {
35 246262 : if (p1->vnn != p2->vnn) {
36 52 : return (p1->vnn < p2->vnn) ? -1 : 1;
37 : }
38 246210 : if (p1->pid != p2->pid) {
39 225096 : return (p1->pid < p2->pid) ? -1 : 1;
40 : }
41 21114 : if (p1->task_id != p2->task_id) {
42 0 : return (p1->task_id < p2->task_id) ? -1 : 1;
43 : }
44 21114 : if (p1->unique_id != p2->unique_id) {
45 0 : return (p1->unique_id < p2->unique_id) ? -1 : 1;
46 : }
47 21114 : return 0;
48 : }
49 :
50 224446 : bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
51 : {
52 224446 : int cmp = server_id_cmp(p1, p2);
53 224446 : return (cmp == 0);
54 : }
55 :
56 204623 : char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
57 : {
58 204623 : if (server_id_is_disconnected(&id)) {
59 0 : strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
60 204623 : } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
61 79658 : snprintf(dst->buf, sizeof(dst->buf), "%llu",
62 79658 : (unsigned long long)id.pid);
63 124965 : } else if (id.vnn == NONCLUSTER_VNN) {
64 124965 : snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
65 124965 : (unsigned long long)id.pid, (unsigned)id.task_id);
66 0 : } else if (id.task_id == 0) {
67 0 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
68 0 : (unsigned)id.vnn, (unsigned long long)id.pid);
69 : } else {
70 0 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu.%u",
71 0 : (unsigned)id.vnn,
72 0 : (unsigned long long)id.pid,
73 0 : (unsigned)id.task_id);
74 : }
75 204623 : return dst->buf;
76 : }
77 :
78 107832 : size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
79 : {
80 : struct server_id_buf idbuf;
81 : char unique_buf[21]; /* 2^64 is 18446744073709551616, 20 chars */
82 : size_t idlen, unique_len, needed;
83 :
84 107832 : server_id_str_buf(id, &idbuf);
85 :
86 107832 : idlen = strlen(idbuf.buf);
87 107832 : unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
88 : id.unique_id);
89 107832 : needed = idlen + unique_len + 2;
90 :
91 107832 : if (buflen >= needed) {
92 53916 : memcpy(buf, idbuf.buf, idlen);
93 53916 : buf[idlen] = '/';
94 53916 : memcpy(buf + idlen + 1, unique_buf, unique_len+1);
95 : }
96 :
97 107832 : return needed;
98 : }
99 :
100 31483 : struct server_id server_id_from_string(uint32_t local_vnn,
101 : const char *pid_string)
102 : {
103 31483 : struct server_id templ = {
104 : .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
105 : };
106 : struct server_id result;
107 : int ret;
108 :
109 : /*
110 : * We accept various forms with 1, 2 or 3 component forms
111 : * because the server_id_str_buf() can print different forms, and
112 : * we want backwards compatibility for scripts that may call
113 : * smbclient.
114 : */
115 :
116 31483 : result = templ;
117 31483 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
118 : &result.vnn, &result.pid, &result.task_id,
119 : &result.unique_id);
120 31483 : if (ret == 4) {
121 0 : return result;
122 : }
123 :
124 31483 : result = templ;
125 31483 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
126 : &result.vnn, &result.pid, &result.task_id);
127 31483 : if (ret == 3) {
128 0 : return result;
129 : }
130 :
131 31483 : result = templ;
132 31483 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
133 : &result.vnn, &result.pid, &result.unique_id);
134 31483 : if (ret == 3) {
135 0 : return result;
136 : }
137 :
138 31483 : result = templ;
139 31483 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
140 : &result.vnn, &result.pid);
141 31483 : if (ret == 2) {
142 0 : return result;
143 : }
144 :
145 31483 : result = templ;
146 31483 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
147 : &result.pid, &result.task_id, &result.unique_id);
148 31483 : if (ret == 3) {
149 1884 : result.vnn = local_vnn;
150 1884 : return result;
151 : }
152 :
153 29599 : result = templ;
154 29599 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
155 : &result.pid, &result.task_id);
156 29599 : if (ret == 2) {
157 0 : result.vnn = local_vnn;
158 0 : return result;
159 : }
160 :
161 29599 : result = templ;
162 29599 : ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
163 : &result.pid, &result.unique_id);
164 29599 : if (ret == 2) {
165 29497 : result.vnn = local_vnn;
166 29497 : return result;
167 : }
168 :
169 102 : result = templ;
170 102 : ret = sscanf(pid_string, "%"SCNu64, &result.pid);
171 102 : if (ret == 1) {
172 84 : result.vnn = local_vnn;
173 84 : return result;
174 : }
175 :
176 18 : if (strcmp(pid_string, "disconnected") == 0) {
177 0 : server_id_set_disconnected(&result);
178 0 : return result;
179 : }
180 :
181 18 : return templ;
182 : }
183 :
184 : /**
185 : * Set the serverid to the special value that represents a disconnected
186 : * client for (e.g.) durable handles.
187 : */
188 233958 : void server_id_set_disconnected(struct server_id *id)
189 : {
190 233958 : *id = (struct server_id) {
191 : .pid = UINT64_MAX,
192 : .task_id = UINT32_MAX,
193 : .vnn = NONCLUSTER_VNN,
194 : .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
195 : };
196 233958 : }
197 :
198 : /**
199 : * check whether a serverid is the special placeholder for
200 : * a disconnected client
201 : */
202 211342 : bool server_id_is_disconnected(const struct server_id *id)
203 : {
204 : struct server_id dis;
205 :
206 211342 : SMB_ASSERT(id != NULL);
207 :
208 211342 : server_id_set_disconnected(&dis);
209 :
210 211342 : return server_id_equal(id, &dis);
211 : }
212 :
213 64025 : void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
214 : const struct server_id id)
215 : {
216 64025 : SBVAL(buf, 0, id.pid);
217 64025 : SIVAL(buf, 8, id.task_id);
218 64025 : SIVAL(buf, 12, id.vnn);
219 64025 : SBVAL(buf, 16, id.unique_id);
220 64025 : }
221 :
222 275956 : void server_id_get(struct server_id *id,
223 : const uint8_t buf[SERVER_ID_BUF_LENGTH])
224 : {
225 275956 : id->pid = BVAL(buf, 0);
226 275956 : id->task_id = IVAL(buf, 8);
227 275956 : id->vnn = IVAL(buf, 12);
228 275956 : id->unique_id = BVAL(buf, 16);
229 275956 : }
|